[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\n\n[*.yml]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "* text=auto eol=lf\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: I think I found a bug in SQLx\ndescription: Create a bug-report issue\nlabels: [bug]\nbody:\n  - type: textarea\n    id: related-issues\n    validations:\n      required: true\n    attributes:\n      label: I have found these related issues/pull requests\n      description: |\n        I have searched by clicking [HERE](https://github.com/launchbadge/sqlx/issues?q=) \n        for existing issues, these are the ones I've found, \n        and this is why I think this deserves a new issue.\n      placeholder: \"Related to ...\"\n  - type: textarea\n    id: description\n    validations:\n      required: true\n    attributes:\n      label: Description\n      description: Clear and concise description of what the bug is\n  - type: textarea\n    id: steps-to-reproduce\n    validations:\n      required: true\n    attributes:\n      label: Reproduction steps\n      description: A small code snippet or a link to a Github repo or Gist, with instructions on reproducing the bug.\n  - type: input\n    id: sqlx-version\n    attributes:\n      label: SQLx version\n    validations:\n      required: true\n  - type: input\n    id: sqlx-features\n    attributes:\n      label: Enabled SQLx features\n    validations:\n      required: true\n  - type: input\n    id: db-server-and-version\n    attributes:\n      label: Database server and version\n      placeholder: MySQL / Postgres / SQLite <x.y.z>\n    validations:\n      required: true\n  - type: input\n    id: os-type\n    attributes:\n      label: Operating system\n    validations:\n      required: true\n  - type: input\n    id: rust-version\n    attributes:\n      label: Rust version\n      description: You can get this via running `rustc --version`\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Enabling some optional features adds unexpected crates to Cargo.lock\n    url: https://github.com/launchbadge/sqlx/issues/3211\n    about: See this issue.\n  - name: I have a question or problem\n    url: https://github.com/launchbadge/sqlx/tree/main/FAQ.md\n    about: See our FAQ.\n  - name: I have a question or problem not covered in the FAQ\n    url: https://github.com/launchbadge/sqlx/discussions/new?category=q-a\n    about: Open a Q&A discussion.\n  - name: Join SQLx's Discord\n    url: https://discord.gg/hPm3WqA\n    about: Join our Discord server for help, discussions and release announcements.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: I have a feature request for SQLx\ndescription: Create a feature-request issue\nlabels: [enhancement]\nbody:\n  - type: textarea\n    id: related-issues\n    validations:\n      required: true\n    attributes:\n      label: I have found these related issues/pull requests\n      description: \"Provide context for your pull request.\"\n      placeholder: |\n          Closes \\#...\n          Relates to \\#...\n  - type: textarea\n    id: feature-description\n    validations:\n      required: true\n    attributes:\n      label: Description\n      description: A clear and concise description of what the problem is\n      placeholder: You should add ...\n  - type: textarea\n    id: solution\n    validations:\n      required: true\n    attributes:\n      label: Prefered solution\n      description: A clear and concise description of what you want to happen.\n      placeholder: In my use-case, ...\n  - type: textarea\n    id: breaking-change\n    validations:\n      required: true\n    attributes:\n      label: Is this a breaking change? Why or why not?\n\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "<!-- \nPR AUTHOR INSTRUCTIONS; PLEASE READ.\n\nGive your pull request an accurate and descriptive title. It should mention what component(s) or database driver(s) it touches.\nPull requests with undescriptive or inaccurate titles *may* be closed or have their titles changed before merging.\n\nFill out the fields below.\n\nAll pull requests *must* pass CI to be merged. Check your pull request frequently for build failures until all checks pass.\nAddress build failures by pushing new commits or amending existing ones. Feel free to ask for help if you get stuck.\nIf a failure seems spurious (timeout or cache failure), you may push a new commit to re-run it.\n\nAfter addressing review comments, re-request review to show that you are ready for your PR to be looked at again.\n\nPull requests which sit for a long time with broken CI or unaddressed review comments will be closed to clear the backlog.\nIf this happens, you are welcome to open a new pull request, but please be sure to address the feedback you have received previously.\n\nBug fixes should include a regression test which fails before the fix and passes afterwards. If this is infeasible, please explain why.\n\nNew features *should* include unit or integration tests in the appropriate folders. Database specific tests should go in `tests/<database>`.\n\nNote that unsolicited pull requests implementing large or complex changes may not be reviwed right away.\nMaintainer time and energy is limited and massive unsolicited pull requests require an outsized effort to review.\n\nTo make the best use of your time and ours, search for and participate in existing discussion on the issue tracker before opening a pull request.\nThe solution you came up with may have already been rejected or postponed due to other work needing to be done first,\nor there may be a pending solution going down a different direction that you hadn't considered.\n\nPull requests that take existing discussion into account are the most likely to be merged.\n\nDelete this block comment before submission to show that you have read and understand these instructions.\n-->\n\n### Does your PR solve an issue?\nDelete this text and add \"fixes #(issue number)\".\n\nDo *not* just list issue numbers here as they will not be automatically closed on merging this pull request unless prefixed with \"fixes\" or \"closes\".\n\n### Is this a breaking change?\nDelete this text and answer yes/no and explain.\n\nIf yes, this pull request will need to wait for the next major release (`0.{x + 1}.0`)\n\nBehavior changes _can_ be breaking if significant enough.\nConsider [Hyrum's Law](https://www.hyrumslaw.com/):\n\n> With a sufficient number of users of an API,  \n> it does not matter what you promise in the contract:  \n> all observable behaviors of your system  \n> will be depended on by somebody.\n"
  },
  {
    "path": ".github/workflows/examples.yml",
    "content": "name: Examples\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n      - '*-dev'\n\njobs:\n  sqlx-cli:\n    name: Build SQLx CLI\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: |\n          rustup show active-toolchain || rustup toolchain install\n          rustup override set stable\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: >\n          cargo build\n          -p sqlx-cli\n          --release\n          --no-default-features\n          --features mysql,postgres,sqlite,sqlx-toml\n\n      - uses: actions/upload-artifact@v4\n        with:\n          name: sqlx-cli\n          path: |\n            target/release/sqlx\n            target/release/cargo-sqlx\n\n  mysql:\n    name: MySQL Examples\n    runs-on: ubuntu-latest\n    needs: sqlx-cli\n    timeout-minutes: 30\n\n    strategy:\n      matrix:\n        offline: ['', 'offline']\n\n    services:\n      mysql:\n        image: mysql:latest\n        env:\n          MYSQL_ROOT_PASSWORD: password\n        ports:\n          - 3306:3306\n\n    steps:\n      - name: Get SQLx-CLI\n        uses: actions/download-artifact@v4\n        with:\n          name: sqlx-cli\n          # $HOME is interpreted differently by the shell\n          path: /home/runner/.local/bin\n\n      - run: |\n          ls -R /home/runner/.local/bin\n          chmod +x /home/runner/.local/bin/sqlx /home/runner/.local/bin/cargo-sqlx\n          echo /home/runner/.local/bin >> $GITHUB_PATH\n          sleep 10\n\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Todos (Setup)\n        working-directory: examples/mysql/todos\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/todos?ssl-mode=disabled\n        run: sqlx db setup\n\n      - name: Todos (Prepare)\n        if: ${{ matrix.offline }}\n        working-directory: examples/mysql/todos\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/todos?ssl-mode=disabled\n        run: cargo sqlx prepare\n\n      - name: Todos (Check Offline)\n        if: ${{ matrix.offline }}\n        run: |\n          cargo clean -p sqlx-example-mysql-todos\n          cargo check -p sqlx-example-mysql-todos\n\n      - name: Todos (Prepare from .env)\n        if: ${{ matrix.offline }}\n        working-directory: examples/mysql/todos\n        run: |\n          echo \"DATABASE_URL=mysql://root:password@localhost:3306/todos?ssl-mode=disabled\" > .env\n          cargo clean -p sqlx-example-mysql-todos\n          cargo sqlx prepare\n          rm .env\n\n      - name: Todos (Run)\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/todos?ssl-mode=disabled\n          SQLX_OFFLINE: ${{ matrix.offline == 'offline' }}\n        run: cargo run -p sqlx-example-mysql-todos\n\n  postgres:\n    name: PostgreSQL Examples\n    runs-on: ubuntu-latest\n    needs: sqlx-cli\n    timeout-minutes: 30\n\n    strategy:\n      matrix:\n        offline: ['', 'offline']\n\n    services:\n      postgres:\n        image: postgres:latest\n        env:\n          POSTGRES_PASSWORD: password\n        ports:\n          - 5432:5432\n\n    steps:\n      - name: Get SQLx-CLI\n        uses: actions/download-artifact@v4\n        with:\n          name: sqlx-cli\n          path: /home/runner/.local/bin\n\n      - run: |\n          ls -R /home/runner/.local/bin\n          chmod +x $HOME/.local/bin/sqlx\n          chmod +x $HOME/.local/bin/cargo-sqlx\n          echo $HOME/.local/bin >> $GITHUB_PATH\n          sleep 10\n\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - name: Axum Social with Tests (Setup)\n        working-directory: examples/postgres/axum-social-with-tests\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/axum-social\n        run: sqlx db setup\n\n      # Test `cargo sqlx prepare` setting `DATABASE_URL` both directly and in `.env`\n      # This doesn't need to be done for every single example here, but should at least cover potential problem cases.\n      - name: Axum Social with Tests (Prepare)\n        if: ${{ matrix.offline }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/axum-social\n        run: cargo sqlx prepare -- -p sqlx-example-postgres-axum-social\n\n      - name: Axum Social with Tests (Check Offline)\n        if: ${{ matrix.offline }}\n        run: |\n          cargo clean -p sqlx-example-postgres-axum-social\n          cargo check -p sqlx-example-postgres-axum-social\n\n      - name: Axum Social with Tests (Prepare from .env)\n        if: ${{ matrix.offline }}\n        run: |\n          echo \"DATABASE_URL=postgres://postgres:password@localhost:5432/axum-social\" > .env\n          cargo clean -p sqlx-example-postgres-axum-social\n          cargo sqlx prepare -- -p sqlx-example-postgres-axum-social\n          rm .env\n\n      - name: Axum Social with Tests (Test)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/axum-social\n          SQLX_OFFLINE: ${{ matrix.offline == 'offline' }}\n        run: cargo test -p sqlx-example-postgres-axum-social\n\n      # The Chat example has an interactive TUI which is not trivial to test automatically,\n      # so we only check that it compiles.\n      - name: Chat (Check)\n        run: cargo check -p sqlx-example-postgres-chat\n\n      - name: Files (Setup)\n        working-directory: examples/postgres/files\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/files\n        run: sqlx db setup\n\n      - name: Files (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/files\n        run: cargo run -p sqlx-example-postgres-files\n\n      - name: JSON (Setup)\n        working-directory: examples/postgres/json\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/json\n        run: sqlx db setup\n\n      - name: JSON (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/json\n        run: cargo run -p sqlx-example-postgres-json\n\n      - name: Listen (Setup)\n        working-directory: examples/postgres/listen\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/listen\n        run: sqlx db create\n\n      - name: Listen (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/listen\n        run: cargo run -p sqlx-example-postgres-listen\n\n      - name: Mockable TODOs (Setup)\n        working-directory: examples/postgres/mockable-todos\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/mockable-todos\n        run: sqlx db setup\n\n      - name: Mockable TODOs (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/mockable-todos\n        run: cargo run -p sqlx-example-postgres-mockable-todos\n\n      - name: Multi-Database (Setup)\n        working-directory: examples/postgres/multi-database\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database\n          ACCOUNTS_DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database-accounts\n          PAYMENTS_DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database-payments\n        run: |\n          (cd accounts && sqlx db setup)\n          (cd payments && sqlx db setup)\n          sqlx db setup\n\n      - name: Multi-Database (Prepare)\n        if: ${{ matrix.offline }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database\n          ACCOUNTS_DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database-accounts\n          PAYMENTS_DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database-payments\n        run: |\n            cargo clean -p sqlx-example-postgres-multi-database-accounts\n            cargo clean -p sqlx-example-postgres-multi-database-payments\n            cargo clean -p sqlx-example-postgres-multi-database\n            # should include -accounts and -payments\n            cargo sqlx prepare -- -p sqlx-example-postgres-multi-database\n\n      - name: Multi-Database (Check Offline)\n        if: ${{ matrix.offline }}\n        run: |\n          cargo clean -p sqlx-example-postgres-multi-database\n          cargo check -p sqlx-example-postgres-multi-database\n\n      - name: Multi-Database (Prepare from .env)\n        if: ${{ matrix.offline }}\n        run: |\n          # Tried to get this to work with heredocs but had trouble writing tabs in YAML\n          echo 'DATABASE_URL=postgres://postgres:password@localhost:5432/multi-database' >.env\n          # Important: append, don't truncate\n          echo 'ACCOUNTS_DATABASE_URL=postgres://postgres:password@localhost:5432/multi-database-accounts' >> .env\n          echo 'PAYMENTS_DATABASE_URL=postgres://postgres:password@localhost:5432/multi-database-payments' >> .env\n          \n          cargo clean -p sqlx-example-postgres-multi-database-accounts\n          cargo clean -p sqlx-example-postgres-multi-database-payments\n          cargo clean -p sqlx-example-postgres-multi-database\n          cargo sqlx prepare -- -p sqlx-example-postgres-multi-database\n          \n          rm .env\n\n      - name: Multi-Database (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database\n          ACCOUNTS_DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database-accounts\n          PAYMENTS_DATABASE_URL: postgres://postgres:password@localhost:5432/multi-database-payments\n          SQLX_OFFLINE: ${{ matrix.offline == 'offline' }}\n        run: cargo run -p sqlx-example-postgres-multi-database\n\n      - name: Multi-Tenant (Setup)\n        working-directory: examples/postgres/multi-tenant\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/multi-tenant\n        run: |\n          (cd accounts && sqlx db setup)\n          (cd payments && sqlx migrate run)\n          sqlx migrate run\n\n      - name: Multi-Tenant (Prepare)\n        if: ${{ matrix.offline }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/multi-tenant\n        run: |\n          cargo clean -p sqlx-example-postgres-multi-tenant-accounts\n          cargo clean -p sqlx-example-postgres-multi-tenant-payments\n          cargo clean -p sqlx-example-postgres-multi-tenant\n          # should include -accounts and -payments\n          cargo sqlx prepare -- -p sqlx-example-postgres-multi-tenant\n\n      - name: Multi-Tenant (Check Offline)\n        if: ${{ matrix.offline }}\n        run: cargo check -p sqlx-example-postgres-multi-tenant\n\n      - name: Multi-Tenant (Prepare from .env)\n        if: ${{ matrix.offline }}\n        run: |\n          echo \"DATABASE_URL=postgres://postgres:password@localhost:5432/multi-tenant\" > .env\n          \n          cargo clean -p sqlx-example-postgres-multi-tenant-accounts\n          cargo clean -p sqlx-example-postgres-multi-tenant-payments\n          cargo clean -p sqlx-example-postgres-multi-tenant\n          # should include -accounts and -payments\n          cargo sqlx prepare -- -p sqlx-example-postgres-multi-tenant\n          \n          rm .env\n\n      - name: Multi-Tenant (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/multi-tenant\n          SQLX_OFFLINE: ${{ matrix.offline == 'offline' }}\n        run: cargo run -p sqlx-example-postgres-multi-tenant\n\n      - name: Preferred-Crates (Setup)\n        working-directory: examples/postgres/preferred-crates\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/preferred-crates\n        run: sqlx db setup\n\n      - name: Preferred-Crates (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/preferred-crates\n        run: cargo run -p sqlx-example-postgres-preferred-crates\n\n      - name: TODOs (Setup)\n        working-directory: examples/postgres/todos\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/todos\n        run: sqlx db setup\n\n      - name: TODOs (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/todos\n        # TODO: test full CLI\n        run: cargo run -p sqlx-example-postgres-todos\n\n      - name: Transaction (Setup)\n        working-directory: examples/postgres/transaction\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/txn\n        run: sqlx db setup\n\n      - name: Transaction (Run)\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/txn\n        run: cargo run -p sqlx-example-postgres-transaction\n\n  sqlite:\n    name: SQLite Examples\n    runs-on: ubuntu-latest\n    needs: sqlx-cli\n    timeout-minutes: 30\n\n    steps:\n      - name: Get SQLx-CLI\n        uses: actions/download-artifact@v4\n        with:\n          name: sqlx-cli\n          path: /home/runner/.local/bin\n\n      - run: |\n          ls -R /home/runner/.local/bin\n          chmod +x /home/runner/.local/bin/sqlx\n          echo /home/runner/.local/bin >> $GITHUB_PATH\n\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: TODOs (Setup)\n        env:\n          DATABASE_URL: sqlite://todos.sqlite\n        run: sqlx db setup --source=examples/sqlite/todos/migrations\n\n      - name: Todos (Prepare)\n        if: ${{ matrix.offline }}\n        env:\n          DATABASE_URL: sqlite://todos.sqlite\n        run: cargo sqlx prepare -- -p sqlx-example-sqlite-todos\n\n      - name: Todos (Check Offline)\n        if: ${{ matrix.offline }}\n        run: |\n          cargo clean -p sqlx-example-sqlite-todos\n          cargo check -p sqlx-example-sqlite-todos\n\n      - name: Todos (Prepare from .env)\n        if: ${{ matrix.offline }}\n        run: |\n          echo \"DATABASE_URL=sqlite://todos.sqlite\" > .env\n          cargo clean -p sqlx-example-sqlite-todos\n          cargo sqlx prepare -- -p sqlx-example-sqlite-todos\n          rm .env\n\n      - name: TODOs (Run)\n        env:\n          DATABASE_URL: sqlite://todos.sqlite\n          SQLX_OFFLINE: ${{ matrix.offline == 'offline' }}\n        run: cargo run -p sqlx-example-sqlite-todos\n"
  },
  {
    "path": ".github/workflows/sqlx-cli.yml",
    "content": "name: SQLx CLI\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n      - \"*-dev\"\n\njobs:\n  check:\n    name: Check\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: |\n          rustup show active-toolchain || rustup toolchain install\n          rustup component add clippy\n          rustup toolchain install beta\n          rustup component add --toolchain beta clippy\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: cargo clippy --manifest-path sqlx-cli/Cargo.toml -- -D warnings\n\n      # Run beta for new warnings but don't break the build.\n      # Use a subdirectory of `target` to avoid clobbering the cache.\n      - run: >\n          cargo +beta clippy\n          --manifest-path sqlx-cli/Cargo.toml\n          --target-dir target/beta/\n\n  integration-test:\n    name: Integration Test\n    runs-on: ${{ matrix.os }}\n\n    strategy:\n      matrix:\n        # Note: macOS-latest uses M1 Silicon (ARM64)\n        os:\n          - ubuntu-latest\n          # FIXME: migrations tests fail on Windows for whatever reason\n          # - windows-latest\n          - macOS-15-intel\n          - macOS-latest\n\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: cargo test --manifest-path sqlx-cli/Cargo.toml\n\n  test-mysql:\n    name: Functional Test (MySQL)\n    runs-on: ubuntu-latest\n    # Deliberately not using `tests/docker-compose.yml` because that sets up the database automatically.\n    services:\n      mysql:\n        image: mysql:8\n        ports:\n          - 3306:3306\n        env:\n          MYSQL_ROOT_PASSWORD: password\n    env:\n      BASE_URL: mysql://root:password@localhost\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Install SQLx-CLI\n        run:\n          cargo install --locked --debug --path sqlx-cli\n\n      - name: Basic Test\n        env:\n          DATABASE_URL: ${{ env.BASE_URL }}/test1\n        run: |\n          sqlx db setup --source=tests/mysql/migrations\n          \n          sqlx mig info --source=tests/mysql/migrations\n          \n          sqlx db drop -y\n\n      - name: Test .env\n        run: |\n          echo \"DATABASE_URL=${{ env.BASE_URL }}/test2\" > .env\n          \n          sqlx db setup --source=tests/mysql/migrations\n          \n          sqlx mig info --source=tests/mysql/migrations\n          \n          sqlx db drop -y\n\n      - name: Test --no-dotenv\n        run: |\n          # Allow subcommands to fail\n          set +e\n          \n          echo \"DATABASE_URL=${{ env.BASE_URL }}/test3\" > .env\n          \n          ERROR=$(sqlx db setup --no-dotenv --source=tests/mysql/migrations)\n          \n          if [[ \"$ERROR\" == *\"--database-url\"* ]]; then\n            exit 0\n          else\n            echo \"Unexpected error from sqlx-cli: $ERROR\"\n            exit 1\n          fi\n\n      - name: Test Reversible Migrations\n        env:\n          DATABASE_URL: ${{ env.BASE_URL }}/test4\n        run: |\n          sqlx db setup --source=tests/mysql/migrations_reversible\n          \n          INFO_BEFORE=$(sqlx mig info --source=tests/mysql/migrations_reversible)\n          \n          sqlx mig revert --target-version=0 --source=tests/mysql/migrations_reversible\n          \n          INFO_AFTER=$(sqlx mig info --source=tests/mysql/migrations_reversible)\n          \n          if [[ \"$INFO_BEFORE\" == \"$INFO_AFTER\" ]]; then\n            echo \"Error: migration info is identical before and after migrating: $INFO_BEFORE\"\n            exit 1\n          fi\n\n  test-postgres:\n    name: Functional Test (PostgreSQL)\n    runs-on: ubuntu-latest\n    # Deliberately not using `tests/docker-compose.yml` because that sets up the database automatically.\n    services:\n      mysql:\n        image: postgres:17\n        ports:\n          - 5432:5432\n        env:\n          POSTGRES_PASSWORD: password\n    env:\n      BASE_URL: postgres://postgres:password@localhost\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Install SQLx-CLI\n        run:\n          cargo install --locked --debug --path sqlx-cli\n\n      - name: Basic Test\n        env:\n          DATABASE_URL: ${{ env.BASE_URL }}/test1\n        run: |\n          sqlx db setup --source=tests/postgres/migrations\n          \n          sqlx mig info --source=tests/postgres/migrations\n          \n          sqlx db drop -y\n\n      - name: Test .env\n        run: |\n          echo \"DATABASE_URL=${{ env.BASE_URL }}/test2\" > .env\n          \n          sqlx db setup --source=tests/postgres/migrations\n          \n          sqlx mig info --source=tests/postgres/migrations\n          \n          sqlx db drop -y\n\n      - name: Test --no-dotenv\n        run: |\n          # Allow subcommands to fail\n          set +e\n          \n          echo \"DATABASE_URL=${{ env.BASE_URL }}/test3\" > .env\n          \n          ERROR=$(sqlx db setup --no-dotenv --source=tests/postgres/migrations)\n          \n          if [[ \"$ERROR\" == *\"--database-url\"* ]]; then\n            exit 0\n          else\n            echo \"Unexpected error from sqlx-cli: $ERROR\"\n            exit 1\n          fi\n\n      - name: Test Reversible Migrations\n        env:\n          DATABASE_URL: ${{ env.BASE_URL }}/test4\n        run: |\n          sqlx db setup --source=tests/postgres/migrations_reversible\n          \n          INFO_BEFORE=$(sqlx mig info --source=tests/postgres/migrations_reversible)\n          \n          sqlx mig revert --target-version=0 --source=tests/postgres/migrations_reversible\n          \n          INFO_AFTER=$(sqlx mig info --source=tests/postgres/migrations_reversible)\n          \n          if [[ \"$INFO_BEFORE\" == \"$INFO_AFTER\" ]]; then\n            echo \"Error: migration info is identical before and after migrating: $INFO_BEFORE\"\n            exit 1\n          fi\n\n  test-sqlite:\n    name: Functional Test (SQLite)\n    runs-on: ubuntu-latest\n    env:\n      BASE_URL: sqlite://.\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Install SQLx-CLI\n        run:\n          cargo install --locked --debug --path sqlx-cli\n\n      - name: Basic Test\n        env:\n          DATABASE_URL: ${{ env.BASE_URL }}/test1\n        run: |\n          sqlx db setup --source=tests/sqlite/migrations\n          \n          sqlx mig info --source=tests/sqlite/migrations\n          \n          sqlx db drop -y\n\n      - name: Test .env\n        run: |\n          echo \"DATABASE_URL=${{ env.BASE_URL }}/test2\" > .env\n          \n          sqlx db setup --source=tests/sqlite/migrations\n          \n          sqlx mig info --source=tests/sqlite/migrations\n          \n          sqlx db drop -y\n\n      - name: Test --no-dotenv\n        run: |\n          # Allow subcommands to fail\n          set +e\n          \n          echo \"DATABASE_URL=${{ env.BASE_URL }}/test3\" > .env\n          \n          ERROR=$(sqlx db setup --no-dotenv --source=tests/sqlite/migrations)\n          \n          if [[ \"$ERROR\" == *\"--database-url\"* ]]; then\n            exit 0\n          else\n            echo \"Unexpected error from sqlx-cli: $ERROR\"\n            exit 1\n          fi\n\n      - name: Test Reversible Migrations\n        env:\n          DATABASE_URL: ${{ env.BASE_URL }}/test4\n        run: |\n          sqlx db setup --source=tests/sqlite/migrations_reversible\n          \n          INFO_BEFORE=$(sqlx mig info --source=tests/sqlite/migrations_reversible)\n          \n          sqlx mig revert --target-version=0 --source=tests/sqlite/migrations_reversible\n          \n          INFO_AFTER=$(sqlx mig info --source=tests/sqlite/migrations_reversible)\n          \n          if [[ \"$INFO_BEFORE\" == \"$INFO_AFTER\" ]]; then\n            echo \"Error: migration info is identical before and after migrating: $INFO_BEFORE\"\n            exit 1\n          fi\n\n  build:\n    name: Build\n    runs-on: ${{ matrix.os }}\n\n    strategy:\n      matrix:\n        # Note: macOS-latest uses M1 Silicon (ARM64)\n        os:\n          - ubuntu-latest\n          - windows-latest\n          - macOS-15-intel\n          - macOS-latest\n        include:\n          - os: ubuntu-latest\n            target: x86_64-unknown-linux-musl\n            args: --features openssl-vendored\n            bin: target/debug/cargo-sqlx\n          - os: windows-latest\n            target: x86_64-pc-windows-msvc\n            bin: target/debug/cargo-sqlx.exe\n          - os: macOS-15-intel\n            target: x86_64-apple-darwin\n            bin: target/debug/cargo-sqlx\n          - os: macOS-latest\n            target: aarch64-apple-darwin\n            bin: target/debug/cargo-sqlx\n\n    timeout-minutes: 30\n\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: |\n          rustup show active-toolchain || rustup toolchain install\n          rustup override set stable\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: cargo build --manifest-path sqlx-cli/Cargo.toml --bin cargo-sqlx ${{ matrix.args }}\n\n      - uses: actions/upload-artifact@v4\n        with:\n          name: cargo-sqlx-${{ matrix.target }}\n          path: ${{ matrix.bin }}\n"
  },
  {
    "path": ".github/workflows/sqlx.yml",
    "content": "name: SQLx\n\non:\n  pull_request:\n  push:\n    branches:\n      - main\n      - \"*-dev\"\n\njobs:\n  format:\n    name: Format\n    runs-on: ubuntu-24.04\n    timeout-minutes: 15\n    steps:\n      - uses: actions/checkout@v4\n      - run: rustup component add rustfmt\n      - run: cargo fmt --all -- --check\n\n  check:\n    name: Check\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        # Note: because `async-std` is deprecated, we only check it in a single job to save CI time.\n        runtime: [ async-std, async-global-executor, smol, tokio ]\n        tls: [ native-tls, rustls, none ]\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      # Swatinem/rust-cache recommends setting up the rust toolchain first because it's used in cache keys\n      - name: Setup Rust\n        # https://blog.rust-lang.org/2025/03/02/Rustup-1.28.0.html\n        run: |\n          rustup show active-toolchain || rustup toolchain install\n          rustup component add clippy\n          rustup toolchain install beta\n          rustup component add --toolchain beta clippy\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: >\n          cargo clippy\n          --no-default-features\n          --features all-databases,_unstable-all-types,sqlite-preupdate-hook,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }},macros\n          -- -D warnings\n\n      # Run beta for new warnings but don't break the build.\n      # Use a subdirectory of `target` to avoid clobbering the cache.\n      - run: >\n          cargo +beta clippy\n          --no-default-features\n          --features all-databases,_unstable-all-types,sqlite-preupdate-hook,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }},macros\n          --target-dir target/beta/\n\n  check-minimal-versions:\n    name: Check build using minimal versions\n    runs-on: ubuntu-24.04\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n      - name: Setup Rust\n        run: |\n          rustup show active-toolchain || rustup toolchain install\n          rustup toolchain install nightly\n      - run: cargo +nightly generate-lockfile -Z minimal-versions\n      - run: cargo build --all-features\n\n  test:\n    name: Unit Tests\n    runs-on: ubuntu-24.04\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      # https://blog.rust-lang.org/2025/03/02/Rustup-1.28.0.html\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Test sqlx-core\n        run: >\n          cargo test\n          -p sqlx-core\n          --all-features      \n\n      - name: Test sqlx-mysql\n        run: >\n          cargo test\n          -p sqlx-mysql\n          --all-features      \n\n      - name: Test sqlx-postgres\n        run: >\n          cargo test\n          -p sqlx-postgres\n          --all-features      \n\n      - name: Test sqlx-sqlite\n        run: >\n          cargo test\n          -p sqlx-sqlite\n          --all-features      \n\n      - name: Test sqlx-macros-core\n        run: >\n          cargo test\n          -p sqlx-macros-core\n          --all-features\n\n      # Note: use `--lib` to not run integration tests that require a DB\n      - name: Test sqlx\n        run: >\n          cargo test\n          -p sqlx\n          --lib\n          --all-features\n\n  sqlite:\n    name: SQLite\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        runtime: [ async-global-executor, smol, tokio ]\n        linking: [ sqlite, sqlite-unbundled ]\n    needs: check\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      - run: mkdir /tmp/sqlite3-lib && wget -O /tmp/sqlite3-lib/ipaddr.so https://github.com/nalgeon/sqlean/releases/download/0.15.2/ipaddr.so\n\n      # https://blog.rust-lang.org/2025/03/02/Rustup-1.28.0.html\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - name: Install system sqlite library\n        if: ${{ matrix.linking == 'sqlite-unbundled' }}\n        run: sudo apt-get install -y libsqlite3-dev\n\n      - run: echo \"using ${DATABASE_URL}\"\n\n      # Create data dir for offline mode\n      - run: mkdir .sqlx\n\n      - run: >\n          cargo test\n          --no-default-features\n          --features any,macros,migrate,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }},${{ matrix.linking == 'sqlite' && 'sqlite-preupdate-hook' || ''}}\n          --\n          --test-threads=1\n        env:\n          DATABASE_URL: sqlite:tests/sqlite/sqlite.db\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg sqlite_ipaddr --cfg sqlite_test_sqlcipher\n          LD_LIBRARY_PATH: /tmp/sqlite3-lib\n\n      # Run the `test-attr` test again to cover cleanup.\n      # The `sqlite-test-attr` test requires the `sqlite` feature.\n      - if: ${{ matrix.linking == 'sqlite' }}\n        run: >\n          cargo test\n          --test sqlite-test-attr\n          --no-default-features\n          --features any,macros,migrate,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }},${{ matrix.linking == 'sqlite' && 'sqlite-preupdate-hook' || ''}}\n          --\n          --test-threads=1\n        env:\n          DATABASE_URL: sqlite:tests/sqlite/sqlite.db\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg sqlite_ipaddr --cfg sqlite_test_sqlcipher\n          LD_LIBRARY_PATH: /tmp/sqlite3-lib\n\n      # Remove test artifacts\n      - run: cargo clean -p sqlx\n\n      # Build the macros-test in offline mode (omit DATABASE_URL)\n      - run: >\n          cargo build\n          --no-default-features\n          --test sqlite-macros\n          --features any,macros,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }}\n        env:\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg sqlite_ipaddr\n          LD_LIBRARY_PATH: /tmp/sqlite3-lib\n\n      # Test macros in offline mode (still needs DATABASE_URL to run)\n      - run: >\n          cargo test\n          --no-default-features\n          --test sqlite-macros\n          --features any,macros,${{ matrix.linking }},_unstable-all-types,runtime-${{ matrix.runtime }}\n        env:\n          DATABASE_URL: sqlite://tests/sqlite/sqlite.db\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg sqlite_ipaddr\n          LD_LIBRARY_PATH: /tmp/sqlite3-lib\n\n  postgres:\n    name: Postgres\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        postgres: [ 17, 13 ]\n        runtime: [ async-global-executor, smol, tokio ]\n        tls: [ native-tls, rustls-aws-lc-rs, rustls-ring, none ]\n    needs: check\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - env:\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n        run: >\n          cargo build \n          --no-default-features\n          --features postgres,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }},macros,migrate\n\n      - run: |\n          docker compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }} postgres_${{ matrix.postgres }}\n\n      - run: |\n          docker exec postgres_${{ matrix.postgres }} bash -c \"until pg_isready; do sleep 1; done\"\n\n      # Create data dir for offline mode\n      - run: mkdir .sqlx\n\n      - run: >\n          cargo test\n          --no-default-features\n          --features any,postgres,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n\n      # Run the `test-attr` test again to cover cleanup.\n      - run: >\n          cargo test\n          --test postgres-test-attr\n          --no-default-features\n          --features any,postgres,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n\n      - if: matrix.tls != 'none'\n        run: >\n          cargo test\n          --no-default-features\n          --features any,postgres,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n\n      # Remove test artifacts\n      - run: cargo clean -p sqlx\n\n      # Build the macros-test in offline mode (omit DATABASE_URL)\n      - run: >\n          cargo build\n          --no-default-features\n          --test postgres-macros\n          --features any,postgres,macros,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n\n      # Test macros in offline mode (still needs DATABASE_URL to run)\n      - run: >\n          cargo test\n          --no-default-features\n          --test postgres-macros\n          --features any,postgres,macros,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/sqlx\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n\n  postgres-ssl-auth:\n    name: Postgres SSL Auth\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        postgres: [ 13, 17 ]\n        runtime: [ async-std, tokio ]\n        tls: [ native-tls, rustls-aws-lc-rs, rustls-ring ]\n    needs: check\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: |\n          docker compose -f tests/docker-compose.yml run -d -p 5432:5432 --name postgres_${{ matrix.postgres }}_client_ssl postgres_${{ matrix.postgres }}_client_ssl\n\n      - run: |\n          docker exec postgres_${{ matrix.postgres }}_client_ssl bash -c \"until pg_isready; do sleep 1; done\"\n\n      - run: >\n          cargo test\n          --no-default-features\n          --features any,postgres,macros,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: postgres://postgres@localhost:5432/sqlx?sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=.%2Ftests%2Fcerts%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt\n          RUSTFLAGS: -D warnings --cfg postgres=\"${{ matrix.postgres }}\"\n\n  mysql:\n    name: MySQL\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        mysql: [ 8 ]\n        runtime: [ async-global-executor, smol, tokio ]\n        tls: [ native-tls, rustls-aws-lc-rs, rustls-ring, none ]\n    needs: check\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: cargo build --features mysql,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n\n      - run: docker compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mysql_${{ matrix.mysql }} mysql_${{ matrix.mysql }}\n      - run: sleep 60\n\n      # Create data dir for offline mode\n      - run: mkdir .sqlx\n\n      - run: >\n          cargo test\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx?ssl-mode=disabled\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mysql_${{ matrix.mysql }}\n\n      # Run the `test-attr` test again to cover cleanup.\n      - run: >\n          cargo test\n          --test mysql-test-attr\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx?ssl-mode=disabled\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mysql_${{ matrix.mysql }}\n\n      # MySQL 5.7 supports TLS but not TLSv1.3 as required by RusTLS.\n      - if: ${{ !(matrix.mysql == '5_7' && matrix.tls == 'rustls') }}\n        run: >\n          cargo test\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mysql_${{ matrix.mysql }}\n\n      # Remove test artifacts\n      - run: cargo clean -p sqlx\n\n      # Build the macros-test in offline mode (omit DATABASE_URL)\n      - run: >\n          cargo build\n          --no-default-features\n          --test mysql-macros\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg mysql_${{ matrix.mysql }}\n\n      # Test macros in offline mode (still needs DATABASE_URL to run)\n      # MySQL 5.7 supports TLS but not TLSv1.3 as required by RusTLS.\n      - run: >\n          cargo test\n          --no-default-features\n          --test mysql-macros\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mysql_${{ matrix.mysql }}\n\n      # client SSL authentication\n\n      - if: ${{ matrix.tls != 'none' }}\n        run: |\n          docker stop mysql_${{ matrix.mysql }}\n          docker compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mysql_${{ matrix.mysql }}_client_ssl mysql_${{ matrix.mysql }}_client_ssl\n          sleep 60\n\n      - if: ${{ matrix.tls != 'none' }}\n        run: >\n          cargo test\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fcerts%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt\n          RUSTFLAGS: --cfg mysql_${{ matrix.mysql }}\n\n  mariadb:\n    name: MariaDB\n    runs-on: ubuntu-24.04\n    strategy:\n      matrix:\n        mariadb: [ verylatest, 11_8, 11_4, 10_11, 10_6 ]\n        runtime: [ async-global-executor, smol, tokio ]\n        tls: [ native-tls, rustls-aws-lc-rs, rustls-ring, none ]\n    needs: check\n    timeout-minutes: 30\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Setup Rust\n        run: rustup show active-toolchain || rustup toolchain install\n\n      - uses: Swatinem/rust-cache@v2\n\n      - run: cargo build --features mysql,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n\n      - run: docker compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mariadb_${{ matrix.mariadb }} mariadb_${{ matrix.mariadb }}\n      - run: sleep 30\n\n      # Create data dir for offline mode\n      - run: mkdir .sqlx\n\n      - run: >\n          cargo test\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mariadb=\"${{ matrix.mariadb }}\"\n\n      # Run the `test-attr` test again to cover cleanup.\n      - run: >\n          cargo test\n          --test mysql-test-attr\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mariadb=\"${{ matrix.mariadb }}\"\n\n      # Remove test artifacts\n      - run: cargo clean -p sqlx\n\n      # Build the macros-test in offline mode (omit DATABASE_URL)\n      - run: >\n          cargo build\n          --no-default-features\n          --test mysql-macros\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: -D warnings --cfg mariadb=\"${{ matrix.mariadb }}\"\n\n      # Test macros in offline mode (still needs DATABASE_URL to run)\n      - run: >\n          cargo test\n          --no-default-features\n          --test mysql-macros\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root:password@localhost:3306/sqlx\n          SQLX_OFFLINE: true\n          SQLX_OFFLINE_DIR: .sqlx\n          RUSTFLAGS: --cfg mariadb=\"${{ matrix.mariadb }}\"\n\n      # client SSL authentication\n\n      - if: ${{ matrix.tls != 'none' }}\n        run: |\n          docker stop mariadb_${{ matrix.mariadb }}\n          docker compose -f tests/docker-compose.yml run -d -p 3306:3306 --name mariadb_${{ matrix.mariadb }}_client_ssl mariadb_${{ matrix.mariadb }}_client_ssl\n          sleep 60\n\n      - if: ${{ matrix.tls != 'none' }}\n        run: >\n          cargo test\n          --no-default-features\n          --features any,mysql,macros,migrate,_unstable-all-types,runtime-${{ matrix.runtime }},tls-${{ matrix.tls }}\n        env:\n          DATABASE_URL: mysql://root@localhost:3306/sqlx?sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fcerts%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt\n          RUSTFLAGS: --cfg mariadb=\"${{ matrix.mariadb }}\"\n"
  },
  {
    "path": ".gitignore",
    "content": "# Built artifacts\ntarget/\n\n# Project and editor files\n.vscode/\n.idea/\n*.vim\n*.vi\n\n# Environment\n.env\n\n# Shared-memory and WAL files created by SQLite.\n*-shm\n*-wal\n\n# Integration testing extension library for SQLite.\nipaddr.dylib\nipaddr.so\n\n# Temporary files from running the tests locally like they would be run from CI\n.sqlx\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n## 0.9.0-alpha.1 - 2025-10-14\n\nAccumulated changes since the beginning of the alpha cycle. Effectively a draft CHANGELOG for the 0.9.0 release.\n\nThis section will be replaced in subsequent alpha releases. See the Git history of this file for previous alphas.\n\n### Breaking\n\n* [[#3383]]: feat: create `sqlx.toml` format [[@abonander]]\n  * SQLx and `sqlx-cli` now support per-crate configuration files (`sqlx.toml`)\n  * New functionality includes, but is not limited to:\n    * Rename `DATABASE_URL` for a crate (for multi-database workspaces) \n    * Set global type overrides for the macros (supporting custom types)\n    * Rename or relocate the `_sqlx_migrations` table (for multiple crates using the same database)\n    * Set characters to ignore when hashing migrations (e.g. ignore whitespace)\n  * More to be implemented in future releases.\n  * Enable feature `sqlx-toml` to use.\n    * `sqlx-cli` has it enabled by default, but `sqlx` does **not**.\n    * Default features of library crates can be hard to completely turn off because of [feature unification], \n      so it's better to keep the default feature set as limited as possible. \n      [This is something we learned the hard way.][preferred-crates]\n  * Guide: see `sqlx::_config` module in documentation.\n  * Reference: [[Link](sqlx-core/src/config/reference.toml)]\n  * Examples (written for Postgres but can be adapted to other databases; PRs welcome!):\n    * Multiple databases using `DATABASE_URL` renaming and global type overrides: [[Link](examples/postgres/multi-database)]\n    * Multi-tenant database using `_sqlx_migrations` renaming and multiple schemas: [[Link](examples/postgres/multi-tenant)]\n    * Force use of `chrono` when `time` is enabled (e.g. when using `tower-sessions-sqlx-store`): [[Link][preferred-crates]]\n      * Forcing `bigdecimal` when `rust_decimal` is enabled is also shown, but problems with `chrono`/`time` are more common.\n  * **Breaking changes**:\n    * Significant changes to the `Migrate` trait\n    * `sqlx::migrate::resolve_blocking()` is now `#[doc(hidden)]` and thus SemVer-exempt.\n* [[#3486]]: fix(logs): Correct spelling of aquired_after_secs tracing field [[@iamjpotts]]\n  * Breaking behavior change: implementations parsing `tracing` logs from SQLx will need to update the spelling.\n* [[#3495]]: feat(postgres): remove lifetime from `PgAdvisoryLockGuard` [[@bonsairobo]]\n* [[#3526]]: Return &mut Self from the migrator set_ methods [[@nipunn1313]]\n  * Minor breaking change: `Migrator::set_ignore_missing` and `set_locking` now return `&mut Self` instead of `&Self`\n    which may break code in rare circumstances.\n* [[#3541]]: Postgres: force generic plan for better nullability inference. [[@joeydewaal]]\n  * Breaking change: may alter the output of the `query!()` macros for certain queries in Postgres.\n* [[#3613]]: fix: `RawSql` lifetime issues [[@abonander]]\n  * Breaking change: adds `DB` type parameter to all methods of `RawSql`\n* [[#3670]]: Bump ipnetwork to v0.21.1 [[@BeauGieskens]]\n* [[#3674]]: Implement `Decode`, `Encode` and `Type` for `Box`, `Arc`, `Cow` and `Rc` [[@joeydewaal]]\n  * Breaking change: `impl Decode for Cow` now always decodes `Cow::Owned`, lifetime is unlinked\n  * See this discussion for motivation: https://github.com/launchbadge/sqlx/pull/3674#discussion_r2008611502\n* [[#3723]]: Add SqlStr [[@joeydewaal]]\n  * Breaking change: all `query*()` functions now take `impl SqlSafeStr` \n    which is only implemented for `&'static str` and `AssertSqlSafe`. \n    For all others, wrap in `AssertSqlSafe(<query>)`.\n  * This, along with [[#3960]], finally allows returning owned queries as the type will be `Query<'static, DB>`.\n  * `SqlSafeStr` trait is deliberately similar to `std::panic::UnwindSafe`, \n    serving as a speedbump to warn users about naïvely building queries with `format!()`\n    while allowing a workaround for advanced usage that is easy to spot on code review. \n* [[#3800]]: Escape PostgreSQL Options [[@V02460]]\n  * Breaking behavior change: options passed to `PgConnectOptions::options()` are now automatically escaped.\n    Manual escaping of options is no longer necessary and may cause incorrect behavior.\n* [[#3821]]: Groundwork for 0.9.0-alpha.1 [[@abonander]]\n  * Increased MSRV to 1.86 and set rust-version\n  * Deleted deprecated combination runtime+TLS features (e.g. `runtime-tokio-native-tls`)\n  * Deleted re-export of unstable `TransactionManager` trait in `sqlx`.\n    * Not technically a breaking change because it's `#[doc(hidden)]`,\n      but [it _will_ break SeaORM][seaorm-2600] if not proactively fixed.\n* [[#3924]]: breaking(mysql): assume all non-binary collations compatible with `str` [[@abonander]]\n  * Text (or text-like) columns which previously were inferred to be `Vec<u8>` will be inferred to be `String` \n    (this should ultimately fix more code than it breaks).\n  * `SET NAMES utf8mb4 COLLATE utf8_general_ci` is no longer sent by default; instead, `SET NAMES utf8mb4` is sent to\n    allow the server to select the appropriate default collation (since this is version- and configuration-dependent).\n  * `MySqlConnectOptions::charset()` and `::collation()` now imply `::set_names(true)` because they don't do anything otherwise.\n  * Setting `charset` doesn't change what's sent in the `Protocol::HandshakeResponse41` packet as that normally only \n    matters for error messages before `SET NAMES` is sent. \n    The default collation if `set_names = false` is `utf8mb4_general_ci`.\n  * See [this comment](https://github.com/launchbadge/sqlx/blob/388c424f486bf20542a8a37d296dbcf86bb6dffd/sqlx-mysql/src/collation.rs#L1-L37) for details.\n  * Incidental breaking change: `RawSql::fetch_optional()` now returns `sqlx::Result<Option<DB::Row>>` \n    instead of `sqlx::Result<DB::Row>`. Whoops.\n* [[#3928]]: breaking(sqlite): `libsqlite3-sys` versioning, feature flags, safety changes [[@abonander]]\n  * SemVer policy changes: `libsqlite3-sys` version is now specified using a range.\n    The maximum of the range may now be increased in any backwards-compatible release.\n    The minimum of the range may only be increased in major releases.\n    If you have `libsqlite3-sys` in your dependencies, Cargo should choose a compatible version automatically. \n    If otherwise unconstrained, Cargo should choose the latest version supported.\n  * SQLite extension loading (including through the new `sqlx-toml` feature) is now `unsafe`. \n  * Added new **non-default** features corresponding to conditionally compiled SQLite APIs:\n    * `sqlite-deserialize` enabling `SqliteConnection::serialize()` and `SqliteConnection::deserialize()`\n    * `sqlite-load-extension` enabling `SqliteConnectOptions::extension()` and `::extension_with_entrypoint()`\n    * `sqlite-unlock-notify` enables internal use of `sqlite3_unlock_notify()`\n  * `SqliteValue` and `SqliteValueRef` changes:\n    * The [`sqlite3_value*` interface](https://www.sqlite.org/c3ref/value_blob.html) reserves the right to be stateful. \n      Without protection, any call could theoretically invalidate values previously returned, leading to dangling pointers.\n    * `SqliteValue` is now `!Sync` and `SqliteValueRef` is `!Send` to prevent data races from concurrent accesses.\n      *  Instead, clone or wrap the `SqliteValue` in `Mutex`, or convert the `SqliteValueRef` to an owned value.\n    * `SqliteValue` and any derived `SqliteValueRef`s now internally track if that value has been used to decode a \n      borrowed `&[u8]` or `&str` and errors if it's used to decode any other type.\n    * This is not expected to affect the vast majority of usages, which should only decode a single type \n      per `SqliteValue`/`SqliteValueRef`.\n    * See new docs on `SqliteValue` for details.\n* [[#3949]]: Postgres: move `PgLTree::from` to `From<Vec<PgLTreeLabel>>` implementation [[@JerryQ17]]\n* [[#3957]]: refactor(sqlite): do not borrow bound values, delete lifetime on `SqliteArguments` [[@iamjpotts]]\n* [[#3958]]: refactor(any): Remove lifetime parameter from AnyArguments [[@iamjpotts]]\n* [[#3960]]: refactor(core): Remove lifetime parameter from Arguments trait [[@iamjpotts]]\n* [[#4008]]: make `#[derive(sqlx::Type)]` automatically generate `impl PgHasArrayType` by default for newtype structs [[@papaj-na-wrotkach]]\n  * Manual implementations of PgHasArrayType for newtypes will conflict with the generated one.\n    Delete the manual impl or add `#[sqlx(no_pg_array)]` where conflicts occur.\n\n### Added\n* [[#3641]]: feat(Postgres): support nested domain types [[@joeydewaal]]\n* [[#3651]]: Add PgBindIter for encoding and use it as the implementation encoding &[T] [[@tylerhawkes]]\n* [[#3675]]: feat: implement Encode, Decode, Type for `Arc<str>` and `Arc<[u8]>` (and `Rc` equivalents) [[@joeydewaal]]\n* [[#3791]]: Smol+async global executor 1.80 dev [[@martin-kolarik]]\n  * Adds `runtime-smol` and `runtime-async-global-executor` features to replace usages of the deprecated `async-std` crate.\n* [[#3859]]: Add more JsonRawValue encode/decode impls. [[@Dirbaio]]\n* [[#3881]]: CLi: made cli-lib modules publicly available for other crates [[@silvestrpredko]]\n* [[#3889]]: Compile-time support for external drivers [[@bobozaur]]\n* [[#3917]]: feat(sqlx.toml): support SQLite extensions in macros and sqlx-cli  [[@djarb]]\n* [[#3918]]: Feature: Add exclusion violation error kind [[@barskern]]\n* [[#3971]]: Allow single-field named structs to be transparent [[@Xiretza]]\n* [[#4015]]: feat(sqlite): `no_tx` migration support [[@AlexTMjugador]]\n* [[#4020]]: Add `Migrator::with_migrations()` constructor [[@xb284524239]]\n\n### Changed\n* [[#3525]]: Remove unnecessary boxfutures [[@joeydewaal]]\n* [[#3867]]: sqlx-postgres: Bump etcetera to 0.10.0 [[@miniduikboot]]\n* [[#3709]]: chore: replace once_cell `OnceCell`/`Lazy` with std `OnceLock`/`LazyLock` [[@paolobarbolini]]\n* [[#3890]]: feat: Unify `Debug` implementations across `PgRow`, `MySqlRow` and `SqliteRow` [[@davidcornu]]\n* [[#3911]]: chore: upgrade async-io to v2.4.1 [[@zebrapurring]]\n* [[#3938]]: Move `QueryLogger` back [[@joeydewaal]]\n* [[#3956]]: chore(sqlite): Remove unused test of removed git2 feature [[@iamjpotts]]\n* [[#3962]]: Give SQLX_OFFLINE_DIR from environment precedence in macros [[@psionic-k]]\n* [[#3968]]: chore(ci): Add timeouts to ci jobs [[@iamjpotts]]\n* [[#4002]]: sqlx-postgres(tests): cleanup 2 unit tests. [[@joeydewaal]]\n* [[#4022]]: refactor: tweaks after #3791 [[@abonander]]\n\n### Fixed\n* [[#3840]]: Fix docs.rs build of sqlx-sqlite [[@gferon]]\n* [[#3848]]: fix(macros): don't mutate environment variables [[@joeydewaal]]\n* [[#3856]]: fix(macros): slightly improve unsupported type error message [[@dyc3]]\n* [[#3857]]: fix(mysql): validate parameter count for prepared statements [[@cvzx]]\n* [[#3861]]: Fix NoHostnameTlsVerifier for rustls 0.23.24 and above [[@elichai]]\n* [[#3863]]: Use unnamed statement in pg when not persistent [[@ThomWright]]\n* [[#3874]]: Further reduce dependency on `futures` and `futures-util` [[@paolobarbolini]]\n* [[#3886]]: fix: use Executor::fetch in QueryAs::fetch [[@bobozaur]]\n* [[#3910]]: feat(ok): add correct handling of ok packets in MYSQL implementation [[@0xfourzerofour]]\n* [[#3914]]: fix: regenerate test certificates [[@abonander]]\n* [[#3915]]: fix: spec_error is used by try_from derive [[@saiintbrisson]]\n* [[#3919]]: fix[sqlx-postgres]: do a checked_mul to prevent panic'ing [[@nhatcher-frequenz]]\n* [[#3923]]: sqlx-mysql: Fix bug in cleanup test db's. [[@joeydewaal]]\n* [[#3950]]: chore: Fix warnings for custom postgres_## cfg flags [[@iamjpotts]]\n* [[#3952]]: `Pool.close`: close all connections before returning [[@jpmelos]]\n* [[#3975]]: fix documentation for rustls native root certificates [[@2ndDerivative]]\n* [[#3977]]: refactor(ci): Use separate job for postgres ssl auth tests [[@iamjpotts]]\n* [[#3980]]: Correctly `ROLLBACK` transaction when dropped during `BEGIN`. [[@kevincox]]\n* [[#3981]]: SQLite: fix transaction level accounting with bad custom command. [[@kevincox]]\n* [[#3986]]: chore(core): Fix docstring for Query::try_bind [[@iamjpotts]]\n* [[#3987]]: chore(deps): Resolve deprecation warning for chrono Date and ymd methods [[@iamjpotts]]\n* [[#3988]]: refactor(sqlite): Resolve duplicate test target warning for macros.rs [[@iamjpotts]]\n* [[#3989]]: chore(deps): Set default-features=false on sqlx in workspace.dependencies [[@iamjpotts]]\n* [[#3991]]: fix(sqlite): regression when decoding nulls [[@abonander]]\n* [[#4006]]: PostgreSQL SASL – run SHA256 in a blocking executor [[@ThomWright]]\n* [[#4007]]: fix(compose): use OS-assigned ports for all conatiners [[@papaj-na-wrotkach]]\n* [[#4009]]: Drop cached db connections in macros upon hitting an error [[@swlynch99]]\n* [[#4024]]: fix(sqlite) Migrate revert with no-transaction [[@Dosenpfand]]\n* [[#4027]]: native tls handshake: build TlsConnector in blocking threadpool [[@daviduebler]]\n* [[#4053]]: fix(macros): smarter `.env` loading, caching, and invalidation [[@abonander]]\n  * Additional credit to [[@AlexTMjugador]] ([[#4018]]) and [[@Diggsey]] ([[#4039]]) for their proposed solutions\n    which served as a useful comparison.\n\n[seaorm-2600]: https://github.com/SeaQL/sea-orm/issues/2600\n[feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification\n[preferred-crates]: examples/postgres/preferred-crates\n\n[#3821]: https://github.com/launchbadge/sqlx/pull/3821\n[#3383]: https://github.com/launchbadge/sqlx/pull/3383\n[#3486]: https://github.com/launchbadge/sqlx/pull/3486\n[#3495]: https://github.com/launchbadge/sqlx/pull/3495\n[#3525]: https://github.com/launchbadge/sqlx/pull/3525\n[#3526]: https://github.com/launchbadge/sqlx/pull/3526\n[#3541]: https://github.com/launchbadge/sqlx/pull/3541\n[#3613]: https://github.com/launchbadge/sqlx/pull/3613\n[#3641]: https://github.com/launchbadge/sqlx/pull/3641\n[#3651]: https://github.com/launchbadge/sqlx/pull/3651\n[#3670]: https://github.com/launchbadge/sqlx/pull/3670\n[#3674]: https://github.com/launchbadge/sqlx/pull/3674\n[#3675]: https://github.com/launchbadge/sqlx/pull/3675\n[#3709]: https://github.com/launchbadge/sqlx/pull/3709\n[#3723]: https://github.com/launchbadge/sqlx/pull/3723\n[#3791]: https://github.com/launchbadge/sqlx/pull/3791\n[#3800]: https://github.com/launchbadge/sqlx/pull/3800\n[#3821]: https://github.com/launchbadge/sqlx/pull/3821\n[#3840]: https://github.com/launchbadge/sqlx/pull/3840\n[#3848]: https://github.com/launchbadge/sqlx/pull/3848\n[#3856]: https://github.com/launchbadge/sqlx/pull/3856\n[#3857]: https://github.com/launchbadge/sqlx/pull/3857\n[#3859]: https://github.com/launchbadge/sqlx/pull/3859\n[#3861]: https://github.com/launchbadge/sqlx/pull/3861\n[#3863]: https://github.com/launchbadge/sqlx/pull/3863\n[#3867]: https://github.com/launchbadge/sqlx/pull/3867\n[#3874]: https://github.com/launchbadge/sqlx/pull/3874\n[#3881]: https://github.com/launchbadge/sqlx/pull/3881\n[#3886]: https://github.com/launchbadge/sqlx/pull/3886\n[#3889]: https://github.com/launchbadge/sqlx/pull/3889\n[#3890]: https://github.com/launchbadge/sqlx/pull/3890\n[#3910]: https://github.com/launchbadge/sqlx/pull/3910\n[#3911]: https://github.com/launchbadge/sqlx/pull/3911\n[#3914]: https://github.com/launchbadge/sqlx/pull/3914\n[#3915]: https://github.com/launchbadge/sqlx/pull/3915\n[#3917]: https://github.com/launchbadge/sqlx/pull/3917\n[#3918]: https://github.com/launchbadge/sqlx/pull/3918\n[#3919]: https://github.com/launchbadge/sqlx/pull/3919\n[#3923]: https://github.com/launchbadge/sqlx/pull/3923\n[#3924]: https://github.com/launchbadge/sqlx/pull/3924\n[#3928]: https://github.com/launchbadge/sqlx/pull/3928\n[#3938]: https://github.com/launchbadge/sqlx/pull/3938\n[#3949]: https://github.com/launchbadge/sqlx/pull/3949\n[#3950]: https://github.com/launchbadge/sqlx/pull/3950\n[#3952]: https://github.com/launchbadge/sqlx/pull/3952\n[#3956]: https://github.com/launchbadge/sqlx/pull/3956\n[#3957]: https://github.com/launchbadge/sqlx/pull/3957\n[#3958]: https://github.com/launchbadge/sqlx/pull/3958\n[#3960]: https://github.com/launchbadge/sqlx/pull/3960\n[#3962]: https://github.com/launchbadge/sqlx/pull/3962\n[#3968]: https://github.com/launchbadge/sqlx/pull/3968\n[#3971]: https://github.com/launchbadge/sqlx/pull/3971\n[#3975]: https://github.com/launchbadge/sqlx/pull/3975\n[#3977]: https://github.com/launchbadge/sqlx/pull/3977\n[#3980]: https://github.com/launchbadge/sqlx/pull/3980\n[#3981]: https://github.com/launchbadge/sqlx/pull/3981\n[#3986]: https://github.com/launchbadge/sqlx/pull/3986\n[#3987]: https://github.com/launchbadge/sqlx/pull/3987\n[#3988]: https://github.com/launchbadge/sqlx/pull/3988\n[#3989]: https://github.com/launchbadge/sqlx/pull/3989\n[#3991]: https://github.com/launchbadge/sqlx/pull/3991\n[#4002]: https://github.com/launchbadge/sqlx/pull/4002\n[#4006]: https://github.com/launchbadge/sqlx/pull/4006\n[#4007]: https://github.com/launchbadge/sqlx/pull/4007\n[#4008]: https://github.com/launchbadge/sqlx/pull/4008\n[#4009]: https://github.com/launchbadge/sqlx/pull/4009\n[#4015]: https://github.com/launchbadge/sqlx/pull/4015\n[#4018]: https://github.com/launchbadge/sqlx/pull/4018\n[#4020]: https://github.com/launchbadge/sqlx/pull/4020\n[#4022]: https://github.com/launchbadge/sqlx/pull/4022\n[#4024]: https://github.com/launchbadge/sqlx/pull/4024\n[#4027]: https://github.com/launchbadge/sqlx/pull/4027\n[#4039]: https://github.com/launchbadge/sqlx/pull/4039\n[#4053]: https://github.com/launchbadge/sqlx/pull/4053\n\n## 0.8.6 - 2025-05-19\n\n9 pull requests were merged this release cycle.\n\n### Added\n* [[#3849]]: Add color and wrapping to cli help text [[@joshka]]\n\n### Changed\n* [[#3830]]: build: drop unused `tempfile` dependency [[@paolobarbolini]]\n* [[#3845]]: chore: clean up no longer used imports [[@tisonkun]]\n* [[#3863]]: Use unnamed statement in pg when not persistent [[@ThomWright]]\n* [[#3866]]: chore(doc): clarify compile-time verification and case conversion behavior [[@duhby]]\n\n### Fixed\n* [[#3840]]: Fix docs.rs build of sqlx-sqlite [[@gferon]]\n* [[#3848]]: fix(macros): don't mutate environment variables [[@joeydewaal]]\n* [[#3855]]: fix `attrubute` typo in doc [[@kujeger]]\n* [[#3856]]: fix(macros): slightly improve unsupported type error message [[@dyc3]]\n\n[#3830]: https://github.com/launchbadge/sqlx/pull/3830\n[#3840]: https://github.com/launchbadge/sqlx/pull/3840\n[#3845]: https://github.com/launchbadge/sqlx/pull/3845\n[#3848]: https://github.com/launchbadge/sqlx/pull/3848\n[#3849]: https://github.com/launchbadge/sqlx/pull/3849\n[#3855]: https://github.com/launchbadge/sqlx/pull/3855\n[#3856]: https://github.com/launchbadge/sqlx/pull/3856\n[#3863]: https://github.com/launchbadge/sqlx/pull/3863\n[#3866]: https://github.com/launchbadge/sqlx/pull/3866\n\n## 0.8.5 - 2025-04-14\n\nHotfix release to address two new issues:\n* [[#3823]]: `sqlx-cli@0.8.4` broke `.env` default resolution mechanism\n* [[#3825]]: `sqlx@0.8.4` broke test fixture setup\n\nThe `0.8.4` release will be yanked as of publishing this one.\n\n### Added\n* In release PR: `sqlx-cli` now accepts `--no-dotenv` in subcommand arguments.\n* In release PR: added functionality tests for `sqlx-cli` to CI.\n* In release PR: test `#[sqlx::test]` twice in CI to cover cleanup.\n\n### Fixed\n* In release PR: `sqlx-cli` correctly reads `.env` files by default again.\n  * Addresses [[#3823]].\n* In release PR: fix bugs in MySQL implementation of `#[sqlx::test]`.\n  * Addresses [[#3825]].\n\n[#3823]: https://github.com/launchbadge/sqlx/issues/3823\n[#3825]: https://github.com/launchbadge/sqlx/issues/3825\n\n## 0.8.4 - 2025-04-13\n\n50 pull requests were merged this release cycle.\n\n### Added\n* [[#3603]]: Added missing special casing for encoding embedded arrays of custom types [[@nico-incubiq]]\n* [[#3625]]: feat(sqlite): add preupdate hook [[@aschey]]\n* [[#3655]]: docs: add example for postgres enums with type TEXT [[@tisonkun]]\n* [[#3677]]: Add json(nullable) macro attribute [[@seanaye]]\n* [[#3687]]: Derive clone and debug for postgresql arguments [[@remysaissy]]\n* [[#3690]]: feat: add postres geometry line segment [[@jayy-lmao]]\n* [[#3707]]: feat(Sqlite): add LockedSqliteHandle::last_error [[@joeydewaal]]\n* [[#3710]]: feat: add ipnet support [[@BeauGieskens]]\n* [[#3711]]: feat(postgres): add geometry box [[@jayy-lmao]]\n* [[#3714]]: chore: expose bstr feature [[@joeydewaal]]\n* [[#3716]]: feat(postgres): add geometry path [[@jayy-lmao]]\n* [[#3724]]: feat(sqlx-cli): Add flag to disable automatic loading of .env files [[@benwilber]]\n* [[#3734]]: QueryBuilder: add debug_assert when `push_values` is passed an empty set of tuples [[@chanmaoganda]]\n* [[#3745]]: feat: sqlx sqlite expose de/serialize [[@mattrighetti]]\n* [[#3765]]: Merge of #3427 (by @mpyw) and #3614 (by @bonsairobo) [[@abonander]]\n    * [[#3427]] Expose `transaction_depth` through `get_transaction_depth()` method [[@mpyw]]\n      * Changed to `Connection::is_in_transaction` in [[#3765]]\n    * [[#3614]] Add `begin_with` methods to support database-specific transaction options [[@bonsairobo]]\n* [[#3769]]: feat(postgres): add geometry polygon [[@jayy-lmao]]\n* [[#3773]]: feat(postgres): add geometry circle [[@jayy-lmao]]\n\n### Changed\n* [[#3665]]: build(deps): bump semver compatible dependencies [[@paolobarbolini]]\n* [[#3669]]: refactor(cli): replace promptly with dialoguer [[@paolobarbolini]]\n* [[#3672]]: add `#[track_caller]` to `Row::get()` [[@karambarakat]]\n* [[#3708]]: chore(MySql): Remove unnecessary box [[@joeydewaal]]\n* [[#3715]]: chore: add pg_copy regression tests [[@joeydewaal]]\n* [[#3721]]: Replace some `futures-core` / `futures-util` APIs with `std` variants [[@paolobarbolini]]\n* [[#3725]]: chore: replace rustls-pemfile with rustls-pki-types [[@tottoto]]\n* [[#3754]]: chore(cli): remove unused async-trait crate from dependencies [[@tottoto]]\n* [[#3762]]: docs(pool): recommend actix-web ThinData over Data to avoid two Arcs [[@jonasmalacofilho]]\n\n### Fixed\n* [[#3289]]: Always set `SQLITE_OPEN_URI` on in-memory sqlite [[@LecrisUT]]\n* [[#3334]]: Fix: nextest cleanup race condition [[@bonega]]\n* [[#3666]]: fix(cli): running tests on 32bit platforms [[@paolobarbolini]]\n* [[#3686]]: fix: handle nullable values by printing NULL instead of panicking [[@joeydewaal]]\n* [[#3700]]: fix(Sqlite): stop sending rows after first error [[@joeydewaal]]\n* [[#3701]]: fix(postgres) use signed int for length prefix in `PgCopyIn` [[@joeydewaal]]\n* [[#3703]]: fix(Postgres) chunk pg_copy data [[@joeydewaal]]\n* [[#3712]]: FromRow: Fix documentation order [[@Turbo87]]\n* [[#3720]]: Fix readme: uuid feature is gating for all repos [[@jthacker]]\n* [[#3728]]: postgres: Fix tracing span when dropping PgListener [[@chitoku-k]]\n* [[#3741]]: Fix example calculation in docs [[@dns2utf8]]\n* [[#3749]]: docs: add some missing backticks [[@soulwa]]\n* [[#3753]]: Avoid privilege requirements by using an advisory lock in test setup (postgres). [[@kildrens]]\n* [[#3755]]: Fix FromRow docs for tuples [[@xvapx]]\n* [[#3768]]: chore(Sqlite): remove ci.db from repo [[@joeydewaal]]\n* [[#3771]]: fix(ci): breakage from Rustup 1.28 [[@abonander]]\n* [[#3786]]: Fix a copy-paste error on get_username docs [[@sulami]]\n* [[#3801]]: Fix: Enable Json type when db feature isn't enabled [[@thriller08]]\n* [[#3809]]: fix: PgConnectOptions docs [[@mbj]]\n* [[#3811]]: Fix error message typo in PgPoint::from_str [[@TeCHiScy]]\n* [[#3812]]: mysql: Fix panic on invalid text row length field [[@0xdeafbeef]]\n* [[#3815]]: fix(macros): cache macro metadata based on `CARGO_MANIFEST_DIR` [[@joeydewaal]]\n* Fixes in release PR [[#3819]] [[@abonander]]:\n  * fix(postgres): send `limit: 0` for all `Execute` messages\n    * Addresses [[#3673]]: Parallel workers not used on Postgres \n  * fix: let `CertificateInput::from` infer any PEM-encoded document\n    * Fixes `PGSSLKEY` not being parsed correctly when containing a PEM-encoded private key.\n  * doc: improve documentation of `PgConnectOptions`\n    * `PGHOSTADDR` now can be used to override `PGHOST`. \n    * Addresses [[#3740]]: Document the URL syntax for Unix-domain sockets when connecting to postgres\n\n[#3819]: https://github.com/launchbadge/sqlx/pull/3819\n\n[#3673]: https://github.com/launchbadge/sqlx/issues/3673\n[#3740]: https://github.com/launchbadge/sqlx/issues/3740\n\n[#3289]: https://github.com/launchbadge/sqlx/pull/3289\n[#3334]: https://github.com/launchbadge/sqlx/pull/3334\n[#3427]: https://github.com/launchbadge/sqlx/pull/3427\n[#3603]: https://github.com/launchbadge/sqlx/pull/3603\n[#3614]: https://github.com/launchbadge/sqlx/pull/3614\n[#3625]: https://github.com/launchbadge/sqlx/pull/3625\n[#3655]: https://github.com/launchbadge/sqlx/pull/3655\n[#3665]: https://github.com/launchbadge/sqlx/pull/3665\n[#3666]: https://github.com/launchbadge/sqlx/pull/3666\n[#3669]: https://github.com/launchbadge/sqlx/pull/3669\n[#3672]: https://github.com/launchbadge/sqlx/pull/3672\n[#3677]: https://github.com/launchbadge/sqlx/pull/3677\n[#3686]: https://github.com/launchbadge/sqlx/pull/3686\n[#3687]: https://github.com/launchbadge/sqlx/pull/3687\n[#3690]: https://github.com/launchbadge/sqlx/pull/3690\n[#3700]: https://github.com/launchbadge/sqlx/pull/3700\n[#3701]: https://github.com/launchbadge/sqlx/pull/3701\n[#3703]: https://github.com/launchbadge/sqlx/pull/3703\n[#3707]: https://github.com/launchbadge/sqlx/pull/3707\n[#3708]: https://github.com/launchbadge/sqlx/pull/3708\n[#3710]: https://github.com/launchbadge/sqlx/pull/3710\n[#3711]: https://github.com/launchbadge/sqlx/pull/3711\n[#3712]: https://github.com/launchbadge/sqlx/pull/3712\n[#3714]: https://github.com/launchbadge/sqlx/pull/3714\n[#3715]: https://github.com/launchbadge/sqlx/pull/3715\n[#3716]: https://github.com/launchbadge/sqlx/pull/3716\n[#3720]: https://github.com/launchbadge/sqlx/pull/3720\n[#3721]: https://github.com/launchbadge/sqlx/pull/3721\n[#3724]: https://github.com/launchbadge/sqlx/pull/3724\n[#3725]: https://github.com/launchbadge/sqlx/pull/3725\n[#3728]: https://github.com/launchbadge/sqlx/pull/3728\n[#3734]: https://github.com/launchbadge/sqlx/pull/3734\n[#3741]: https://github.com/launchbadge/sqlx/pull/3741\n[#3745]: https://github.com/launchbadge/sqlx/pull/3745\n[#3749]: https://github.com/launchbadge/sqlx/pull/3749\n[#3753]: https://github.com/launchbadge/sqlx/pull/3753\n[#3754]: https://github.com/launchbadge/sqlx/pull/3754\n[#3755]: https://github.com/launchbadge/sqlx/pull/3755\n[#3762]: https://github.com/launchbadge/sqlx/pull/3762\n[#3765]: https://github.com/launchbadge/sqlx/pull/3765\n[#3768]: https://github.com/launchbadge/sqlx/pull/3768\n[#3769]: https://github.com/launchbadge/sqlx/pull/3769\n[#3771]: https://github.com/launchbadge/sqlx/pull/3771\n[#3773]: https://github.com/launchbadge/sqlx/pull/3773\n[#3786]: https://github.com/launchbadge/sqlx/pull/3786\n[#3801]: https://github.com/launchbadge/sqlx/pull/3801\n[#3809]: https://github.com/launchbadge/sqlx/pull/3809\n[#3811]: https://github.com/launchbadge/sqlx/pull/3811\n[#3812]: https://github.com/launchbadge/sqlx/pull/3812\n[#3815]: https://github.com/launchbadge/sqlx/pull/3815\n\n## 0.8.3 - 2025-01-03\n\n41 pull requests were merged this release cycle.\n\n### Added\n* [[#3418]]: parse timezone parameter in mysql connection url [[@dojiong]]\n* [[#3491]]: chore: Update async-std v1.13 [[@jayvdb]]\n* [[#3492]]: expose relation_id and relation_attribution_no on PgColumn [[@kurtbuilds]]\n* [[#3493]]: doc(sqlite): document behavior for zoned date-time types [[@abonander]]\n* [[#3500]]: Add sqlite commit and rollback hooks [[@gridbox]]\n* [[#3505]]: chore(mysql): create test for passwordless auth (#3484) [[@abonander]]\n* [[#3507]]: Add a \"sqlite-unbundled\" feature that dynamically links to system libsqlite3.so library [[@lilydjwg]]\n* [[#3508]]: doc(sqlite): show how to turn options into a pool [[@M3t0r]]\n* [[#3514]]: Support PgHstore by default in macros [[@joeydewaal]]\n* [[#3550]]: Implement Acquire for PgListener [[@sandhose]]\n* [[#3551]]: Support building with rustls but native certificates [[@IlyaBizyaev]]\n* [[#3553]]: Add support for Postgres lquery arrays [[@philipcristiano]]\n* [[#3560]]: Add PgListener::next_buffered(), to support batch processing of notifications [[@chanks]]\n* [[#3577]]: Derive Copy where possible for database-specific types [[@veigaribo]]\n* [[#3579]]: Reexport AnyTypeInfoKind [[@Norlock]]\n* [[#3580]]: doc(mysql): document difference between `Uuid` and `uuid::fmt::Hyphenated` [[@abonander]]\n* [[#3583]]: feat: point [[@jayy-lmao]]\n* [[#3608]]: Implement AnyQueryResult for Sqlite and MySQL [[@pxp9]]\n* [[#3623]]: feat: add geometry line [[@jayy-lmao]]\n* [[#3658]]: feat: add Transaction type aliases [[@joeydewaal]]\n\n### Changed\n* [[#3519]]: Remove unused dependencies from sqlx-core, sqlx-cli and sqlx-postgres [[@vsuryamurthy]]\n* [[#3529]]: Box Pgconnection fields [[@joeydewaal]]\n* [[#3548]]: Demote `.pgpass` file warning to a debug message. [[@denschub]]\n* [[#3585]]: Eagerly reconnect in `PgListener::try_recv` [[@swlynch99]]\n* [[#3596]]: Bump thiserror to v2.0.0 [[@paolobarbolini]]\n* [[#3605]]: Use `UNION ALL` instead of `UNION` in nullable check [[@Suficio]]\n* [[#3629]]: chore: remove BoxFuture's (non-breaking) [[@joeydewaal]]\n* [[#3632]]: Bump hashlink to v0.10 [[@paolobarbolini]]\n* [[#3643]]: Roll PostgreSQL 11..=15 tests to 13..=17 [[@paolobarbolini]]\n* [[#3648]]: close listener connection on TimedOut and BrokenPipe errors [[@DXist]]\n* [[#3649]]: Bump hashbrown to v0.15 [[@paolobarbolini]]\n\n### Fixed\n* [[#3528]]: fix: obey `no-transaction` flag in down migrations [[@manifest]]\n* [[#3536]]: fix: using sqlx::test macro inside macro's [[@joeydewaal]]\n* [[#3545]]: fix: remove `sqlformat` [[@tbar4]]\n* [[#3558]]: fix: fix example code of `query_as` [[@xuehaonan27]]\n* [[#3566]]: Fix: Cannot query Postgres `INTERVAL[]` [[@Ddystopia]]\n* [[#3593]]: fix: URL decode database name when parsing connection url [[@BenoitRanque]]\n* [[#3601]]: Remove default-features = false from url [[@hsivonen]]\n* [[#3604]]: Fix mistake in sqlx::test fixtures docs [[@andreweggleston]]\n* [[#3612]]: fix(mysql): percent-decode database name [[@abonander]]\n* [[#3640]]: Dont use `EXPLAIN` in nullability check for QuestDB [[@Suficio]]\n\n[#3418]: https://github.com/launchbadge/sqlx/pull/3418\n[#3478]: https://github.com/launchbadge/sqlx/pull/3478\n[#3491]: https://github.com/launchbadge/sqlx/pull/3491\n[#3492]: https://github.com/launchbadge/sqlx/pull/3492\n[#3493]: https://github.com/launchbadge/sqlx/pull/3493\n[#3500]: https://github.com/launchbadge/sqlx/pull/3500\n[#3505]: https://github.com/launchbadge/sqlx/pull/3505\n[#3507]: https://github.com/launchbadge/sqlx/pull/3507\n[#3508]: https://github.com/launchbadge/sqlx/pull/3508\n[#3514]: https://github.com/launchbadge/sqlx/pull/3514\n[#3519]: https://github.com/launchbadge/sqlx/pull/3519\n[#3528]: https://github.com/launchbadge/sqlx/pull/3528\n[#3529]: https://github.com/launchbadge/sqlx/pull/3529\n[#3536]: https://github.com/launchbadge/sqlx/pull/3536\n[#3545]: https://github.com/launchbadge/sqlx/pull/3545\n[#3548]: https://github.com/launchbadge/sqlx/pull/3548\n[#3550]: https://github.com/launchbadge/sqlx/pull/3550\n[#3551]: https://github.com/launchbadge/sqlx/pull/3551\n[#3553]: https://github.com/launchbadge/sqlx/pull/3553\n[#3558]: https://github.com/launchbadge/sqlx/pull/3558\n[#3560]: https://github.com/launchbadge/sqlx/pull/3560\n[#3566]: https://github.com/launchbadge/sqlx/pull/3566\n[#3577]: https://github.com/launchbadge/sqlx/pull/3577\n[#3579]: https://github.com/launchbadge/sqlx/pull/3579\n[#3580]: https://github.com/launchbadge/sqlx/pull/3580\n[#3583]: https://github.com/launchbadge/sqlx/pull/3583\n[#3585]: https://github.com/launchbadge/sqlx/pull/3585\n[#3593]: https://github.com/launchbadge/sqlx/pull/3593\n[#3596]: https://github.com/launchbadge/sqlx/pull/3596\n[#3601]: https://github.com/launchbadge/sqlx/pull/3601\n[#3604]: https://github.com/launchbadge/sqlx/pull/3604\n[#3605]: https://github.com/launchbadge/sqlx/pull/3605\n[#3608]: https://github.com/launchbadge/sqlx/pull/3608\n[#3612]: https://github.com/launchbadge/sqlx/pull/3612\n[#3623]: https://github.com/launchbadge/sqlx/pull/3623\n[#3629]: https://github.com/launchbadge/sqlx/pull/3629\n[#3632]: https://github.com/launchbadge/sqlx/pull/3632\n[#3640]: https://github.com/launchbadge/sqlx/pull/3640\n[#3643]: https://github.com/launchbadge/sqlx/pull/3643\n[#3648]: https://github.com/launchbadge/sqlx/pull/3648\n[#3649]: https://github.com/launchbadge/sqlx/pull/3649\n[#3658]: https://github.com/launchbadge/sqlx/pull/3658\n\n\n## 0.8.2 - 2024-09-02\n\n10 pull requests were merged this release cycle.\n\nThis release addresses a few regressions that have occurred, and refines SQLx's MSRV policy (see [the FAQ](FAQ.md)).\n\n### Added\n* [[#3447]]: Clarify usage of Json/Jsonb in query macros [[@Lachstec]]\n\n### Changed\n* [[#3424]]: Remove deprecated feature-names from `Cargo.toml` files in examples [[@carschandler]]\n\n### Fixed\n* [[#3403]]: Fix (#3395) sqlx::test macro in 0.8 [[@joeydewaal]]\n* [[#3411]]: fix: Use rfc3339 to decode date from text [[@pierre-wehbe]]\n* [[#3453]]: fix(#3445): PgHasArrayType [[@joeydewaal]]\n    * Fixes `#[sqlx(no_pg_array)]` being forbidden on `#[derive(Type)]` structs. \n* [[#3454]]: fix: non snake case warning [[@joeydewaal]]\n* [[#3459]]: Pgsql cube type compile fail [[@kdesjard]]\n* [[#3465]]: fix(postgres): max number of binds is 65535, not 32767 (regression) [[@abonander]]\n* [[#3467]]: fix cancellation issues with `PgListener`, `PgStream::recv()` [[@abonander]]\n    * Fixes cryptic `unknown message: \"\\\\0\"` error \n* [[#3474]]: Fix try_get example in README.md [[@luveti]]\n\n[#3403]: https://github.com/launchbadge/sqlx/pull/3403\n[#3411]: https://github.com/launchbadge/sqlx/pull/3411\n[#3424]: https://github.com/launchbadge/sqlx/pull/3424\n[#3447]: https://github.com/launchbadge/sqlx/pull/3447\n[#3453]: https://github.com/launchbadge/sqlx/pull/3453\n[#3454]: https://github.com/launchbadge/sqlx/pull/3454\n[#3455]: https://github.com/launchbadge/sqlx/pull/3455\n[#3459]: https://github.com/launchbadge/sqlx/pull/3459\n[#3465]: https://github.com/launchbadge/sqlx/pull/3465\n[#3467]: https://github.com/launchbadge/sqlx/pull/3467\n[#3474]: https://github.com/launchbadge/sqlx/pull/3474\n\n## 0.8.1 - 2024-08-23\n\n16 pull requests were merged this release cycle.\n\nThis release contains a fix for [RUSTSEC-2024-0363]. \n\nPostgres users are advised to upgrade ASAP as a possible exploit has been demonstrated:\n<https://github.com/launchbadge/sqlx/issues/3440#issuecomment-2307956901>\n\nMySQL and SQLite do not _appear_ to be exploitable, but upgrading is recommended nonetheless.\n\n### Added\n* [[#3421]]: correct spelling of `MySqlConnectOptions::no_engine_substitution()` [[@kolinfluence]]\n    * Deprecates `MySqlConnectOptions::no_engine_subsitution()` (oops) in favor of the correctly spelled version.\n\n### Changed\n* [[#3376]]: doc: hide `spec_error` module [[@abonander]]\n    * This is a helper module for the macros and was not meant to be exposed.\n    * It is not expected to receive any breaking changes for the 0.8.x release, but is not designed as a public API.\n      Use at your own risk.\n* [[#3382]]: feat: bumped to `libsqlite3-sys=0.30.1` to support sqlite 3.46 [[@CommanderStorm]]\n* [[#3385]]: chore(examples):Migrated the pg-chat example to ratatui [[@CommanderStorm]]\n* [[#3399]]: Upgrade to rustls 0.23 [[@djc]]\n    * RusTLS now has pluggable cryptography providers: `ring` (the existing implementation),\n      and `aws-lc-rs` which has optional FIPS certification.\n    * The existing features activating RusTLS (`runtime-tokio-rustls`, `runtime-async-std-rustls`, `tls-rustls`)\n      enable the `ring` provider of RusTLS to match the existing behavior so this _should not_ be a breaking change. \n    * Switch to the `tls-rustls-aws-lc-rs` feature to use the `aws-lc-rs` provider.\n      * If using `runtime-tokio-rustls` or `runtime-async-std-rustls`, \n        this will necessitate switching to the appropriate non-legacy runtime feature: \n        `runtime-tokio` or `runtime-async-std`\n    * See the RusTLS README for more details: <https://github.com/rustls/rustls?tab=readme-ov-file#cryptography-providers>\n\n### Fixed\n* [[#2786]]: fix(sqlx-cli): do not clean sqlx during prepare [[@cycraig]]\n* [[#3354]]: sqlite: fix inconsistent read-after-write [[@ckampfe]]\n* [[#3371]]: Fix encoding and decoding of MySQL enums in `sqlx::Type` [[@alu]]\n* [[#3374]]: fix: usage of `node12` in `SQLx` action [[@hamirmahal]]\n* [[#3380]]: chore: replace structopt with clap in examples [[@tottoto]]\n* [[#3381]]: Fix CI after Rust 1.80, remove dead feature references [[@abonander]]\n* [[#3384]]: chore(tests): fixed deprecation warnings [[@CommanderStorm]]\n* [[#3386]]: fix(dependencys):bumped cargo_metadata to `v0.18.1` to avoid yanked `v0.14.3` [[@CommanderStorm]]\n* [[#3389]]: fix(cli): typo in error for required DB URL [[@ods]]\n* [[#3417]]: Update version to 0.8 in README [[@soucosmo]]\n* [[#3441]]: fix: audit protocol handling [[@abonander]]\n    * This addresses [RUSTSEC-2024-0363] and includes regression tests for MySQL, Postgres and SQLite.\n\n[#2786]: https://github.com/launchbadge/sqlx/pull/2786\n[#3354]: https://github.com/launchbadge/sqlx/pull/3354\n[#3371]: https://github.com/launchbadge/sqlx/pull/3371\n[#3374]: https://github.com/launchbadge/sqlx/pull/3374\n[#3376]: https://github.com/launchbadge/sqlx/pull/3376\n[#3380]: https://github.com/launchbadge/sqlx/pull/3380\n[#3381]: https://github.com/launchbadge/sqlx/pull/3381\n[#3382]: https://github.com/launchbadge/sqlx/pull/3382\n[#3384]: https://github.com/launchbadge/sqlx/pull/3384\n[#3385]: https://github.com/launchbadge/sqlx/pull/3385\n[#3386]: https://github.com/launchbadge/sqlx/pull/3386\n[#3389]: https://github.com/launchbadge/sqlx/pull/3389\n[#3399]: https://github.com/launchbadge/sqlx/pull/3399\n[#3417]: https://github.com/launchbadge/sqlx/pull/3417\n[#3421]: https://github.com/launchbadge/sqlx/pull/3421\n[#3441]: https://github.com/launchbadge/sqlx/pull/3441\n\n[RUSTSEC-2024-0363]: https://rustsec.org/advisories/RUSTSEC-2024-0363.html\n\n## 0.8.0 - 2024-07-22\n\n70 pull requests were merged this release cycle.\n\n[#2697] was merged the same day as release 0.7.4 and so was missed by the automatic CHANGELOG generation.\n\n### Breaking\n* [[#2697]]: fix(macros): only enable chrono when time is disabled [[@saiintbrisson]]\n* [[#2973]]: Generic Associated Types in Database, replacing HasValueRef, HasArguments, HasStatement [[@nitn3lav]]\n* [[#2482]]: chore: bump syn to 2.0 [[@saiintbrisson]]\n    * Deprecated type ascription syntax in the query macros was removed.\n* [[#2736]]: Fix describe on PostgreSQL views with rules [[@tsing]]\n  * Potentially breaking: nullability inference changes for Postgres.\n* [[#2869]]: Implement PgHasArrayType for all references [[@tylerhawkes]]\n    * Conflicts with existing manual implementations.\n* [[#2940]]: fix: Decode and Encode derives (#1031) [[@benluelo]]\n    * Changes lifetime obligations for field types.\n* [[#3064]]: Sqlite explain graph [[@tyrelr]]\n    * Potentially breaking: nullability inference changes for SQLite.\n* [[#3123]]: Reorder attrs in sqlx::test macro [[@bobozaur]]\n    * Potentially breaking: attributes on `#[sqlx::test]` usages are applied in the correct order now.\n* [[#3126]]: Make Encode return a result [[@FSMaxB]]\n* [[#3130]]: Add version information for failed cli migration (#3129) [[@FlakM]]\n    * Breaking changes to `MigrateError`.\n* [[#3181]]: feat: no tx migration [[@cleverjam]]\n    * (Postgres only) migrations that should not run in a transaction can be flagged by adding `-- no-transaction` to the beginning.\n    * Breaking change: added field to `Migration`\n* [[#3184]]: [BREAKING} fix(sqlite): always use `i64` as intermediate when decoding [[@abonander]]\n    * integer decoding will now loudly error on overflow instead of silently truncating.\n    * some usages of the query!() macros might change an i32 to an i64.\n* [[#3252]]: fix `#[derive(sqlx::Type)]` in Postgres [[@abonander]]\n  * Manual implementations of PgHasArrayType for enums will conflict with the generated one. Delete the manual impl or add `#[sqlx(no_pg_array)]` where conflicts occur.\n  * Type equality for PgTypeInfo is now schema-aware.\n* [[#3329]]: fix: correct handling of arrays of custom types in Postgres [[@abonander]]\n    * Potential breaking change: `PgTypeInfo::with_name()` infers types that start with `_` to be arrays of the un-prefixed type. Wrap type names in quotes to bypass this behavior.\n* [[#3356]]: breaking: fix name collision in `FromRow`, return `Error::ColumnDecode` for `TryFrom` errors [[@abonander]]\n    * Breaking behavior change: errors with `#[sqlx(try_from = \"T\")]` now return `Error::ColumnDecode` instead of `Error::ColumnNotFound`.\n    * Breaking because `#[sqlx(default)]` on an individual field or the struct itself would have previously suppressed the error. \n      This doesn't seem like good behavior as it could result in some potentially very difficult bugs.\n      * Instead, create a wrapper implementing `From` and apply the default explicitly.\n* [[#3337]]: allow rename with rename_all (close #2896) [[@DirectorX]]\n    * Changes the precedence of `#[sqlx(rename)]` and `#[sqlx(rename_all)]` to match the expected behavior (`rename` wins).\n* [[#3285]]: fix: use correct names for sslmode options [[@lily-mosquitoes]]\n    * Changes the output of `ConnectOptions::to_url_lossy()` to match what parsing expects.\n\n### Added\n* [[#2917]]: Add Debug impl for PgRow [[@g-bartoszek]]\n* [[#3113]]: feat: new derive feature flag [[@saiintbrisson]]\n* [[#3154]]: feat: add `MySqlTime`, audit `mysql::types` for panics [[@abonander]]\n* [[#3188]]: feat(cube): support postgres cube [[@jayy-lmao]]\n* [[#3244]]: feat: support `NonZero*` scalar types [[@AlphaKeks]]\n* [[#3260]]: feat: Add set_update_hook on SqliteConnection [[@gridbox]]\n* [[#3291]]: feat: support the Postgres Bool type for the Any driver [[@etorreborre]]\n* [[#3293]]: Add LICENSE-* files to crates [[@LecrisUT]]\n* [[#3303]]: add array support for NonZeroI* in postgres [[@JohannesIBK]]\n* [[#3311]]: Add example on how to use Transaction as Executor [[@Lachstec]]\n* [[#3343]]: Add support for PostgreSQL HSTORE data type [[@KobusEllis]]\n\n### Changed\n* [[#2652]]: MySQL: Remove collation compatibility check for strings [[@alu]]\n* [[#2960]]: Removed `Send` trait bound from argument binding [[@bobozaur]]\n* [[#2970]]: refactor: lift type mappings into driver crates [[@abonander]]\n* [[#3148]]: Bump libsqlite3-sys to v0.28 [[@NfNitLoop]]\n    * Note: version bumps to `libsqlite3-sys` are not considered breaking changes as per our semver guarantees.\n* [[#3265]]: perf: box `MySqlConnection` to reduce sizes of futures [[@stepantubanov]]\n* [[#3352]]: chore:added a testcase for `sqlx migrate add ...` [[@CommanderStorm]]\n* [[#3340]]: ci: Add job to check that sqlx builds with its declared minimum dependencies [[@iamjpotts]]\n\n### Fixed\n* [[#2702]]: Constrain cyclic associated types to themselves [[@BadBastion]]\n* [[#2954]]: Fix several inter doc links [[@ralpha]]\n* [[#3073]]: feat(logging): Log slow acquires from connection pool [[@iamjpotts]]\n* [[#3137]]: SqliteConnectOptions::filename() memory fix (#3136) [[@hoxxep]]\n* [[#3138]]: PostgreSQL Bugfix: Ensure connection is usable after failed COPY inside a transaction [[@feikesteenbergen]]\n* [[#3146]]: fix(sqlite): delete unused `ConnectionHandleRaw` type [[@abonander]]\n* [[#3162]]: Drop urlencoding dependency [[@paolobarbolini]]\n* [[#3165]]: Bump deps that do not need code changes [[@GnomedDev]]\n* [[#3167]]: fix(ci): use `docker compose` instead of `docker-compose` [[@abonander]]\n* [[#3172]]: fix: Option decoding in any driver [[@pxp9]]\n* [[#3173]]: fix(postgres) : int type conversion while decoding [[@RaghavRox]]\n* [[#3190]]: Update time to 0.3.36 [[@BlackSoulHub]]\n* [[#3191]]: Fix unclean TLS shutdown [[@levkk]]\n* [[#3194]]: Fix leaking connections in fetch_optional (#2647) [[@danjpgriffin]]\n* [[#3216]]: security: bump rustls to 0.21.11 [[@toxeus]]\n* [[#3230]]: fix: sqlite pragma order for auto_vacuum [[@jasonish]]\n* [[#3233]]: fix: get_filename should not consume self [[@jasonish]]\n* [[#3234]]: fix(ci): pin Rust version, ditch unmaintained actions [[@abonander]]\n* [[#3236]]: fix: resolve `path` ownership problems when using `sqlx_macros_unstable` [[@lily-mosquitoes]]\n* [[#3254]]: fix: hide `sqlx_postgres::any` [[@Zarathustra2]]\n* [[#3266]]: ci: MariaDB - add back 11.4 and add 11.5 [[@grooverdan]]\n* [[#3267]]: ci: syntax fix [[@grooverdan]]\n* [[#3271]]: docs(sqlite): fix typo - unixtime() -> unixepoch() [[@joelkoen]]\n* [[#3276]]: Invert boolean for `migrate` error message. (#3275) [[@nk9]]\n* [[#3279]]: fix Clippy errors [[@abonander]]\n* [[#3288]]: fix: sqlite update_hook char types [[@jasonish]]\n* [[#3297]]: Pass the `persistent` query setting when preparing queries with the `Any` driver [[@etorreborre]]\n* [[#3298]]: Track null arguments in order to provide the appropriate type when converting them. [[@etorreborre]]\n* [[#3312]]: doc: Minor rust docs fixes [[@SrGesus]]\n* [[#3327]]: chore: fixed one usage of `select_input_type!()` being unhygenic [[@CommanderStorm]]\n* [[#3328]]: fix(ci): comment not separated from other characters [[@hamirmahal]]\n* [[#3341]]: refactor: Resolve cargo check warnings in postgres examples [[@iamjpotts]]\n* [[#3346]]: fix(postgres): don't panic if `M` or `C` Notice fields are not UTF-8 [[@YgorSouza]]\n* [[#3350]]: fix:the `json`-feature should activate `sqlx-postgres?/json` as well [[@CommanderStorm]]\n* [[#3353]]: fix: build script new line at eof [[@Zarthus]]\n* (no PR): activate `clock` and `std` features of `workspace.dependencies.chrono`.\n\n[#2482]: https://github.com/launchbadge/sqlx/pull/2482\n[#2652]: https://github.com/launchbadge/sqlx/pull/2652\n[#2697]: https://github.com/launchbadge/sqlx/pull/2697\n[#2702]: https://github.com/launchbadge/sqlx/pull/2702\n[#2736]: https://github.com/launchbadge/sqlx/pull/2736\n[#2869]: https://github.com/launchbadge/sqlx/pull/2869\n[#2917]: https://github.com/launchbadge/sqlx/pull/2917\n[#2940]: https://github.com/launchbadge/sqlx/pull/2940\n[#2954]: https://github.com/launchbadge/sqlx/pull/2954\n[#2960]: https://github.com/launchbadge/sqlx/pull/2960\n[#2970]: https://github.com/launchbadge/sqlx/pull/2970\n[#2973]: https://github.com/launchbadge/sqlx/pull/2973\n[#3064]: https://github.com/launchbadge/sqlx/pull/3064\n[#3073]: https://github.com/launchbadge/sqlx/pull/3073\n[#3113]: https://github.com/launchbadge/sqlx/pull/3113\n[#3123]: https://github.com/launchbadge/sqlx/pull/3123\n[#3126]: https://github.com/launchbadge/sqlx/pull/3126\n[#3130]: https://github.com/launchbadge/sqlx/pull/3130\n[#3137]: https://github.com/launchbadge/sqlx/pull/3137\n[#3138]: https://github.com/launchbadge/sqlx/pull/3138\n[#3146]: https://github.com/launchbadge/sqlx/pull/3146\n[#3148]: https://github.com/launchbadge/sqlx/pull/3148\n[#3154]: https://github.com/launchbadge/sqlx/pull/3154\n[#3162]: https://github.com/launchbadge/sqlx/pull/3162\n[#3165]: https://github.com/launchbadge/sqlx/pull/3165\n[#3167]: https://github.com/launchbadge/sqlx/pull/3167\n[#3172]: https://github.com/launchbadge/sqlx/pull/3172\n[#3173]: https://github.com/launchbadge/sqlx/pull/3173\n[#3181]: https://github.com/launchbadge/sqlx/pull/3181\n[#3184]: https://github.com/launchbadge/sqlx/pull/3184\n[#3188]: https://github.com/launchbadge/sqlx/pull/3188\n[#3190]: https://github.com/launchbadge/sqlx/pull/3190\n[#3191]: https://github.com/launchbadge/sqlx/pull/3191\n[#3194]: https://github.com/launchbadge/sqlx/pull/3194\n[#3216]: https://github.com/launchbadge/sqlx/pull/3216\n[#3230]: https://github.com/launchbadge/sqlx/pull/3230\n[#3233]: https://github.com/launchbadge/sqlx/pull/3233\n[#3234]: https://github.com/launchbadge/sqlx/pull/3234\n[#3236]: https://github.com/launchbadge/sqlx/pull/3236\n[#3244]: https://github.com/launchbadge/sqlx/pull/3244\n[#3252]: https://github.com/launchbadge/sqlx/pull/3252\n[#3254]: https://github.com/launchbadge/sqlx/pull/3254\n[#3260]: https://github.com/launchbadge/sqlx/pull/3260\n[#3265]: https://github.com/launchbadge/sqlx/pull/3265\n[#3266]: https://github.com/launchbadge/sqlx/pull/3266\n[#3267]: https://github.com/launchbadge/sqlx/pull/3267\n[#3271]: https://github.com/launchbadge/sqlx/pull/3271\n[#3276]: https://github.com/launchbadge/sqlx/pull/3276\n[#3279]: https://github.com/launchbadge/sqlx/pull/3279\n[#3285]: https://github.com/launchbadge/sqlx/pull/3285\n[#3288]: https://github.com/launchbadge/sqlx/pull/3288\n[#3291]: https://github.com/launchbadge/sqlx/pull/3291\n[#3293]: https://github.com/launchbadge/sqlx/pull/3293\n[#3297]: https://github.com/launchbadge/sqlx/pull/3297\n[#3298]: https://github.com/launchbadge/sqlx/pull/3298\n[#3303]: https://github.com/launchbadge/sqlx/pull/3303\n[#3311]: https://github.com/launchbadge/sqlx/pull/3311\n[#3312]: https://github.com/launchbadge/sqlx/pull/3312\n[#3327]: https://github.com/launchbadge/sqlx/pull/3327\n[#3328]: https://github.com/launchbadge/sqlx/pull/3328\n[#3329]: https://github.com/launchbadge/sqlx/pull/3329\n[#3337]: https://github.com/launchbadge/sqlx/pull/3337\n[#3340]: https://github.com/launchbadge/sqlx/pull/3340\n[#3341]: https://github.com/launchbadge/sqlx/pull/3341\n[#3343]: https://github.com/launchbadge/sqlx/pull/3343\n[#3346]: https://github.com/launchbadge/sqlx/pull/3346\n[#3350]: https://github.com/launchbadge/sqlx/pull/3350\n[#3352]: https://github.com/launchbadge/sqlx/pull/3352\n[#3353]: https://github.com/launchbadge/sqlx/pull/3353\n[#3356]: https://github.com/launchbadge/sqlx/pull/3356\n## 0.7.4 - 2024-03-11\n\n38 pull requests were merged this release cycle.\n\nThis is officially the **last** release of the 0.7.x release cycle.\n\nAs of this release, development of 0.8.0 has begun on `main` and only high-priority bugfixes may be backported.\n\n### Added\n\n* [[#2891]]: feat: expose getters for connect options fields [[@saiintbrisson]]\n* [[#2902]]: feat: add `to_url_lossy` to connect options [[@lily-mosquitoes]]\n* [[#2927]]: Support `query!` for cargo-free systems [[@kshramt]]\n* [[#2997]]: doc(FAQ): add entry explaining prepared statements [[@abonander]]\n* [[#3001]]: Update README to clarify MariaDB support [[@iangilfillan]]\n* [[#3004]]: feat(logging): Add numeric elapsed time field elapsed_secs [[@iamjpotts]]\n* [[#3007]]: feat: add `raw_sql` API [[@abonander]]\n    * This hopefully makes it easier to find how to execute statements which are not supported by the default\n      prepared statement interfaces `query*()` and `query!()`.\n    * Improved documentation across the board for the `query*()` functions.\n    * Deprecated: `execute_many()` and `fetch_many()` on interfaces that use prepared statements.\n        * Multiple SQL statements in one query string were only supported by SQLite because its prepared statement\n          interface is the *only* way to execute SQL. All other database flavors forbid multiple statements in\n          one prepared statement string as an extra defense against SQL injection.\n        * The new `raw_sql` API retains this functionality because it explicitly does *not* use prepared statements.\n          Raw or text-mode query interfaces generally allow multiple statements in one query string, and this is\n          supported by all current databases. Due to their nature, however, one cannot use bind parameters with them.\n        * If this change affects you, an issue is open for discussion: https://github.com/launchbadge/sqlx/issues/3108\n* [[#3011]]: Added support to IpAddr with MySQL/MariaDB. [[@Icerath]]\n* [[#3013]]: Add default implementation for PgInterval [[@pawurb]]\n* [[#3018]]: Add default implementation for PgMoney [[@pawurb]]\n* [[#3026]]: Update docs to reflect support for MariaDB data types [[@iangilfillan]]\n* [[#3037]]: feat(mysql): allow to connect with mysql driver without default behavor [[@darkecho731]]\n\n### Changed\n\n* [[#2900]]: Show latest url to docs for macro.migrate [[@Vrajs16]]\n* [[#2914]]: Use `create_new` instead of `atomic-file-write` [[@mattfbacon]]\n* [[#2926]]: docs: update example for `PgConnectOptions` [[@Fyko]]\n* [[#2989]]: sqlx-core: Remove dotenvy dependency [[@joshtriplett]]\n* [[#2996]]: chore: Update ahash to 0.8.7 [[@takenoko-gohan]]\n* [[#3006]]: chore(deps): Replace unmaintained tempdir crate with tempfile [[@iamjpotts]]\n* [[#3008]]: chore: Ignore .sqlx folder created by running ci steps locally [[@iamjpotts]]\n* [[#3009]]: chore(dev-deps): Upgrade env_logger from 0.9 to 0.11 [[@iamjpotts]]\n* [[#3010]]: chore(deps): Upgrade criterion to 0.5.1 [[@iamjpotts]]\n* [[#3050]]: Optimize SASL auth in sqlx-postgres [[@mirek26]]\n* [[#3055]]: Set TCP_NODELAY option on TCP sockets [[@mirek26]]\n* [[#3065]]: Improve max_lifetime handling [[@mirek26]]\n* [[#3072]]: Change the name of \"inner\" function generated by `#[sqlx::test]` [[@ciffelia]]\n* [[#3083]]: Remove sha1 because it's not being used in postgres [[@rafaelGuerreiro]]\n\n### Fixed\n\n* [[#2898]]: Fixed docs [[@Vrajs16]]\n* [[#2905]]: fix(mysql): Close prepared statement if persistence is disabled [[@larsschumacher]]\n* [[#2913]]: Fix handling of deferred constraints [[@Thomasdezeeuw]]\n* [[#2919]]: fix duplicate \"`\" in FromRow \"default\" attribute doc comment [[@shengsheng]]\n* [[#2932]]: fix(postgres): avoid unnecessary flush in PgCopyIn::read_from [[@tsing]]\n* [[#2955]]: Minor fixes [[@Dawsoncodes]]\n* [[#2963]]: Fixed ReadMe badge styling [[@tadghh]]\n* [[#2976]]: fix: AnyRow not support PgType::Varchar [[@holicc]]\n* [[#3053]]: fix: do not panic when binding a large BigDecimal [[@Ekleog]]\n* [[#3056]]: fix: spans in sqlite tracing (#2876) [[@zoomiti]]\n* [[#3089]]: fix(migrate): improve error message when parsing version from filename [[@abonander]]\n* [[#3098]]: Migrations fixes [[@abonander]]\n  * Unhides `sqlx::migrate::Migrator`.\n  * Improves I/O error message when failing to read a file in `migrate!()`.\n\n[#2891]: https://github.com/launchbadge/sqlx/pull/2891\n[#2898]: https://github.com/launchbadge/sqlx/pull/2898\n[#2900]: https://github.com/launchbadge/sqlx/pull/2900\n[#2902]: https://github.com/launchbadge/sqlx/pull/2902\n[#2905]: https://github.com/launchbadge/sqlx/pull/2905\n[#2913]: https://github.com/launchbadge/sqlx/pull/2913\n[#2914]: https://github.com/launchbadge/sqlx/pull/2914\n[#2919]: https://github.com/launchbadge/sqlx/pull/2919\n[#2926]: https://github.com/launchbadge/sqlx/pull/2926\n[#2927]: https://github.com/launchbadge/sqlx/pull/2927\n[#2932]: https://github.com/launchbadge/sqlx/pull/2932\n[#2955]: https://github.com/launchbadge/sqlx/pull/2955\n[#2963]: https://github.com/launchbadge/sqlx/pull/2963\n[#2976]: https://github.com/launchbadge/sqlx/pull/2976\n[#2989]: https://github.com/launchbadge/sqlx/pull/2989\n[#2996]: https://github.com/launchbadge/sqlx/pull/2996\n[#2997]: https://github.com/launchbadge/sqlx/pull/2997\n[#3001]: https://github.com/launchbadge/sqlx/pull/3001\n[#3004]: https://github.com/launchbadge/sqlx/pull/3004\n[#3006]: https://github.com/launchbadge/sqlx/pull/3006\n[#3007]: https://github.com/launchbadge/sqlx/pull/3007\n[#3008]: https://github.com/launchbadge/sqlx/pull/3008\n[#3009]: https://github.com/launchbadge/sqlx/pull/3009\n[#3010]: https://github.com/launchbadge/sqlx/pull/3010\n[#3011]: https://github.com/launchbadge/sqlx/pull/3011\n[#3013]: https://github.com/launchbadge/sqlx/pull/3013\n[#3018]: https://github.com/launchbadge/sqlx/pull/3018\n[#3026]: https://github.com/launchbadge/sqlx/pull/3026\n[#3037]: https://github.com/launchbadge/sqlx/pull/3037\n[#3050]: https://github.com/launchbadge/sqlx/pull/3050\n[#3053]: https://github.com/launchbadge/sqlx/pull/3053\n[#3055]: https://github.com/launchbadge/sqlx/pull/3055\n[#3056]: https://github.com/launchbadge/sqlx/pull/3056\n[#3065]: https://github.com/launchbadge/sqlx/pull/3065\n[#3072]: https://github.com/launchbadge/sqlx/pull/3072\n[#3083]: https://github.com/launchbadge/sqlx/pull/3083\n[#3089]: https://github.com/launchbadge/sqlx/pull/3089\n[#3098]: https://github.com/launchbadge/sqlx/pull/3098\n\n## 0.7.3 - 2023-11-22\n\n38 pull requests were merged this release cycle.\n\n### Added\n* [[#2478]]: feat(citext): support postgres citext [[@hgranthorner]]\n* [[#2545]]: Add `fixtures_path` in sqlx::test args [[@ripa1995]]\n* [[#2665]]: feat(mysql): support packet splitting [[@tk2217]]\n* [[#2752]]: Enhancement #2747 Provide `fn PgConnectOptions::get_host(&self)` [[@boris-lok]]\n* [[#2769]]: Customize the macro error message based on the metadata [[@Nemo157]]\n* [[#2793]]: derived Hash trait for PgInterval [[@yasamoka]]\n* [[#2801]]: derive FromRow: sqlx(default) for all fields [[@grgi]]\n* [[#2827]]: Add impl `FromRow` for the unit type [[@nanoqsh]]\n* [[#2871]]: Add `MySqlConnectOptions::get_database()`  [[@shiftrightonce]]\n* [[#2873]]: Sqlx Cli: Added force flag to drop database for postgres [[@Vrajs16]]\n* [[#2894]]: feat: `Text` adapter [[@abonander]]\n\n### Changed\n* [[#2701]]: Remove documentation on offline feature [[@Baptistemontan]]\n* [[#2713]]: Add additional info regarding using Transaction and PoolConnection as… [[@satwanjyu]]\n* [[#2770]]: Update README.md [[@snspinn]]\n* [[#2797]]: doc(mysql): document behavior regarding `BOOLEAN` and the query macros [[@abonander]]\n* [[#2803]]: Don't use separate temp dir for query jsons (2)  [[@mattfbacon]]\n* [[#2819]]: postgres begin cancel safe [[@conradludgate]]\n* [[#2832]]: Update extra_float_digits default to 2 instead of 3 [[@brianheineman]]\n* [[#2865]]: Update Faq - Bulk upsert with optional fields  [[@Vrajs16]]\n* [[#2880]]: feat: use specific message for slow query logs [[@abonander]]\n* [[#2882]]: Do not require db url for prepare [[@tamasfe]]\n* [[#2890]]: doc(sqlite): cover lack of `NUMERIC` support [[@abonander]]\n* [No PR]: Upgraded `libsqlite3-sys` to 0.27.0\n  * Note: linkage to `libsqlite3-sys` is considered semver-exempt; \n    see the release notes for 0.7.0 below for details.\n\n### Fixed\n* [[#2640]]: fix: sqlx::macro db cleanup race condition by adding a margin to current timestamp [[@fhsgoncalves]]\n* [[#2655]]: [fix] Urlencode when passing filenames to sqlite3 [[@uttarayan21]]\n* [[#2684]]: Make PgListener recover from UnexpectedEof [[@hamiltop]]\n* [[#2688]]: fix: Make rust_decimal and bigdecimal decoding more lenient [[@cameronbraid]]\n* [[#2754]]: Is tests/x.py maintained? And I tried fix it. [[@qwerty2501]]\n* [[#2784]]: fix: decode postgres time without subsecond [[@granddaifuku]]\n* [[#2806]]: Depend on version of async-std with non-private spawn-blocking [[@A248]]\n* [[#2820]]: fix: correct decoding of `rust_decimal::Decimal` for high-precision values [[@abonander]]\n* [[#2822]]: issue #2821 Update error handling logic when opening a TCP connection [[@anupj]]\n* [[#2826]]: chore: bump some sqlx-core dependencies [[@djc]]\n* [[#2838]]: Fixes rust_decimal scale for Postgres [[@jkleinknox]]\n* [[#2847]]: Fix comment in `sqlx migrate add` help text [[@cryeprecision]]\n* [[#2850]]: fix(core): avoid unncessary wakeups in `try_stream!()` [[@abonander]]\n* [[#2856]]: Prevent warnings running `cargo build` [[@nyurik]]\n* [[#2864]]: fix(sqlite): use `AtomicUsize` for thread IDs [[@abonander]]\n* [[#2892]]: Fixed force dropping bug [[@Vrajs16]]\n\n[#2478]: https://github.com/launchbadge/sqlx/pull/2478\n[#2545]: https://github.com/launchbadge/sqlx/pull/2545\n[#2640]: https://github.com/launchbadge/sqlx/pull/2640\n[#2655]: https://github.com/launchbadge/sqlx/pull/2655\n[#2665]: https://github.com/launchbadge/sqlx/pull/2665\n[#2684]: https://github.com/launchbadge/sqlx/pull/2684\n[#2688]: https://github.com/launchbadge/sqlx/pull/2688\n[#2701]: https://github.com/launchbadge/sqlx/pull/2701\n[#2713]: https://github.com/launchbadge/sqlx/pull/2713\n[#2752]: https://github.com/launchbadge/sqlx/pull/2752\n[#2754]: https://github.com/launchbadge/sqlx/pull/2754\n[#2769]: https://github.com/launchbadge/sqlx/pull/2769\n[#2770]: https://github.com/launchbadge/sqlx/pull/2770\n[#2782]: https://github.com/launchbadge/sqlx/pull/2782\n[#2784]: https://github.com/launchbadge/sqlx/pull/2784\n[#2793]: https://github.com/launchbadge/sqlx/pull/2793\n[#2797]: https://github.com/launchbadge/sqlx/pull/2797\n[#2801]: https://github.com/launchbadge/sqlx/pull/2801\n[#2803]: https://github.com/launchbadge/sqlx/pull/2803\n[#2806]: https://github.com/launchbadge/sqlx/pull/2806\n[#2819]: https://github.com/launchbadge/sqlx/pull/2819\n[#2820]: https://github.com/launchbadge/sqlx/pull/2820\n[#2822]: https://github.com/launchbadge/sqlx/pull/2822\n[#2826]: https://github.com/launchbadge/sqlx/pull/2826\n[#2827]: https://github.com/launchbadge/sqlx/pull/2827\n[#2832]: https://github.com/launchbadge/sqlx/pull/2832\n[#2838]: https://github.com/launchbadge/sqlx/pull/2838\n[#2847]: https://github.com/launchbadge/sqlx/pull/2847\n[#2850]: https://github.com/launchbadge/sqlx/pull/2850\n[#2856]: https://github.com/launchbadge/sqlx/pull/2856\n[#2864]: https://github.com/launchbadge/sqlx/pull/2864\n[#2865]: https://github.com/launchbadge/sqlx/pull/2865\n[#2871]: https://github.com/launchbadge/sqlx/pull/2871\n[#2873]: https://github.com/launchbadge/sqlx/pull/2873\n[#2880]: https://github.com/launchbadge/sqlx/pull/2880\n[#2882]: https://github.com/launchbadge/sqlx/pull/2882\n[#2890]: https://github.com/launchbadge/sqlx/pull/2890\n[#2892]: https://github.com/launchbadge/sqlx/pull/2892\n[#2894]: https://github.com/launchbadge/sqlx/pull/2894\n\n## 0.7.2 - 2023-09-25\n\n23 pull requests were merged this release cycle.\n\n### Added\n\n* [[#2121]]: Add JSON support to `FromRow` derive [[@95ulisse]]\n* [[#2533]]: Implement mysql_clear_password [[@ldanilek]]\n* [[#2538]]: cli: add --target-version CLI flags for migrate run/revert [[@inahga]]\n* [[#2577]]: supplement Postgres listen example with a small chat example [[@JockeM]]\n* [[#2602]]: Support naming migrations sequentially [[@vmax]]\n* [[#2634]]: Adding PgHasArrayType for &[u8;N] [[@snf]]\n* [[#2646]]: Support for setting client certificate and key from bytes [[@wyhaya]]\n* [[#2664]]: Automatically infer migration type [[@vmax]]\n* [[#2712]]: Add impl for `Type`, `Decode`, and `Encode` for `Box<str>` and `Box<[u8]>` [[@grant0417]]\n\n### Changed\n* [[#2650]]: Cleanup format arguments [[@nyurik]]\n* [[#2695]]: remove &mut PoolConnection from Executor docs [[@olback]]\n    * This impl was removed in 0.7.0 because of coherence issues.\n* [[#2706]]: Clarify where optional features should be enabled [[@kryptan]]\n* [[#2717]]: Update README.md [[@fermanjj]]\n* [[#2739]]: Bump mariadb CI images + mysql unpin [[@grooverdan]]\n* [[#2742]]: Implemented poll_flush for Box<S:Socket> [[@bobozaur]]\n* [[#2740]]: Remove sealed trait comments from documentation [[@bobozaur]]\n* [[#2750]]: Fix #2384, bump flume to v0.11.0 [[@madadam]]\n* [[#2757]]: Remove unused `remove_dir_all` crate from `sqlx-cli`, fixes RUSTSEC-2023-0018 [[@aldur]]\n\n### Fixed\n\n* [[#2624]]: Documentation typo: BYTE -> BINARY [[@sebastianv89]]\n* [[#2628]]: docs: 0.7 is stable in the entire README [[@marcusirgens]]\n* [[#2630]]: fix(postgres): fix buffer management in PgCopyIn::read_from [[@tsing]]\n* [[#2651]]: Chore: Fix few build warnings, and make CI fail on warn [[@nyurik]]\n* [[#2670]]: fix: ignore extra fields in Postgres describe parsing [[@abonander]]\n* [[#2687]]: docs: Fix description of `min_connections` [[@hakoerber]]\n\n[#2121]: https://github.com/launchbadge/sqlx/pull/2121\n[#2533]: https://github.com/launchbadge/sqlx/pull/2533\n[#2538]: https://github.com/launchbadge/sqlx/pull/2538\n[#2577]: https://github.com/launchbadge/sqlx/pull/2577\n[#2602]: https://github.com/launchbadge/sqlx/pull/2602\n[#2624]: https://github.com/launchbadge/sqlx/pull/2624\n[#2628]: https://github.com/launchbadge/sqlx/pull/2628\n[#2630]: https://github.com/launchbadge/sqlx/pull/2630\n[#2634]: https://github.com/launchbadge/sqlx/pull/2634\n[#2646]: https://github.com/launchbadge/sqlx/pull/2646\n[#2650]: https://github.com/launchbadge/sqlx/pull/2650\n[#2651]: https://github.com/launchbadge/sqlx/pull/2651\n[#2664]: https://github.com/launchbadge/sqlx/pull/2664\n[#2670]: https://github.com/launchbadge/sqlx/pull/2670\n[#2687]: https://github.com/launchbadge/sqlx/pull/2687\n[#2695]: https://github.com/launchbadge/sqlx/pull/2695\n[#2706]: https://github.com/launchbadge/sqlx/pull/2706\n[#2712]: https://github.com/launchbadge/sqlx/pull/2712\n[#2717]: https://github.com/launchbadge/sqlx/pull/2717\n[#2739]: https://github.com/launchbadge/sqlx/pull/2739\n[#2740]: https://github.com/launchbadge/sqlx/pull/2740\n[#2742]: https://github.com/launchbadge/sqlx/pull/2742\n[#2750]: https://github.com/launchbadge/sqlx/pull/2750\n[#2757]: https://github.com/launchbadge/sqlx/pull/2757\n\n## 0.7.1 - 2023-07-14\n\nThis release mainly addresses issues reported with the 0.7.0 release.\n\n16 pull requests were merged this release cycle.\n\n### Added\n* [[#2551]]: Introduce build_query_scalar for QueryBuilder [[@iamquang95]]\n* [[#2605]]: Implement Default for QueryBuilder [[@Xydez]]\n* [[#2616]]: feat(sqlx-core): add table function to database error [[@saiintbrisson]]\n* [[#2619]]: feat: allow opt-out of `PgHasArrayType` with `#[derive(sqlx::Type)]` [[@abonander]]\n  * TL;DR: if you're getting errors from `#[derive(sqlx::Type)]` with `#[sqlx(transparent)]`\n    regarding `PgHasArrayType` not being implemented, add `#[sqlx(no_pg_array)]` to fix.\n\n### Changed\n* [[#2566]]: improve docs about migration files [[@jnnnnn]]\n* [[#2576]]: Major Version Update clap to 4.0 [[@titaniumtraveler]]\n* [[#2597]]: Bump webpki-roots to v0.24 [[@paolobarbolini]]\n* [[#2603]]: docs(changelog): be more verbose about offline mode breaking change [[@mrl5]]\n\n### Fixed\n* [[#2553]]: Implement `Clone` for `PoolOptions` manually (#2548) [[@alilleybrinker]]\n* [[#2580]]: Update README.md now that 0.7.0 is no longer in alpha [[@saolof]]\n* [[#2585]]: Fix for Issue #2549 - cannot use feature \"rust_decimal\" without also using \"bigdecimal\" [[@deneut]]\n* [[#2586]]: Fix optional dependency on sqlx-macros [[@kitterion]]\n* [[#2593]]: Correct mention of the `tls-native-tls` in the documentation. [[@denschub]]\n* [[#2599]]: Remove incorrect CAST in test database cleanup for MySQL. [[@fd]]\n* [[#2613]]: Fix readme.md to reduce confusion about optional features (decimal->rust_decimal) [[@vabka]]\n* [[#2620]]: fix(sqlite/any): encode bool as integer [[@saiintbrisson]]\n\n[#2551]: https://github.com/launchbadge/sqlx/pull/2551\n[#2553]: https://github.com/launchbadge/sqlx/pull/2553\n[#2566]: https://github.com/launchbadge/sqlx/pull/2566\n[#2576]: https://github.com/launchbadge/sqlx/pull/2576\n[#2580]: https://github.com/launchbadge/sqlx/pull/2580\n[#2585]: https://github.com/launchbadge/sqlx/pull/2585\n[#2586]: https://github.com/launchbadge/sqlx/pull/2586\n[#2593]: https://github.com/launchbadge/sqlx/pull/2593\n[#2597]: https://github.com/launchbadge/sqlx/pull/2597\n[#2599]: https://github.com/launchbadge/sqlx/pull/2599\n[#2603]: https://github.com/launchbadge/sqlx/pull/2603\n[#2605]: https://github.com/launchbadge/sqlx/pull/2605\n[#2613]: https://github.com/launchbadge/sqlx/pull/2613\n[#2616]: https://github.com/launchbadge/sqlx/pull/2616\n[#2619]: https://github.com/launchbadge/sqlx/pull/2619\n[#2620]: https://github.com/launchbadge/sqlx/pull/2620\n\n## 0.7.0 - 2023-06-30\n\nAt least **70 pull requests** were merged this release cycle! (The exact count is muddied with pull requests for alpha\nreleases and such.) And we gained 43 new contributors! Thank you to everyone who helped make this release a reality.\n\n### Breaking\nMany revisions were made to query analysis in the SQLite driver; these are all potentially breaking changes\nas they can change the output of `sqlx::query!()` _et al_. We'd like to thank [[@tyrelr]] for their numerous PRs to\nthis area.\n\nThe MSSQL driver has been removed as it was not nearly at the same maturity level as the other drivers.\n[As previously announced][sqlx-pro], we have plans to introduce a fully featured replacement as a premium offering,\nalongside drivers for other proprietary databases, with the goal to support full-time development on SQLx. \n\nIf interested, please email your inquiry to sqlx@launchbadge.com.\n\nThe offline mode for the queries has been changed to use a separate file per `query!()` invocation,\nwhich is intended to reduce the number of conflicts when merging branches in a project that both modified queries.\nThis means that CLI flag `--merged` is no longer supported. See [[#2363]] for details and make sure that your\n`sqlx-cli` version is in sync with the `sqlx` version in your project.\n\nThe type ascription override syntax for the query macros has been deprecated,\nas parse support for it has been removed in `syn 2.0`, which we'll be upgrading to in the next breaking release. \nThis can be replaced with type overrides using casting syntax (`as`). \nSee [[#2483]] for details.\n\n* [[#1946]]: Fix compile time verification performance regression for sqlite [[@liningpan]]\n* [[#1960]]: Fix sqlite update return and order by type inference [[@tyrelr]]\n* [[#1984]]: Sqlite EXPLAIN type inference improvements [[@rongcuid]]\n* [[#2039]]: Break drivers out into separate crates, clean up some technical debt [[@abonander]]\n    * All deprecated items have been removed.\n    * The `mssql` feature and associated database driver has been deleted from the source tree. It will return as part of our planned SQLx Pro offering as a from-scratch rewrite with extra features (such as TLS) and type integrations that were previously missing.\n    * The `runtime-actix-*` features have been deleted. They were previously changed to be aliases of their `runtime-tokio-*` counterparts for backwards compatibility reasons, but their continued existence is misleading as SQLx has no special knowledge of Actix anymore.\n        * To fix, simply replace the `runtime-actix-*` feature with its `runtime-tokio-*` equivalent.\n    * The `git2` feature has been removed. This was a requested integration from a while ago that over time made less and less sense to be part of SQLx itself. We have to be careful with the crates we add to our public API as each one introduces yet another semver hazard. The expected replacement is to make `#[derive(sqlx::Type)]` useful enough that users can write wrapper types for whatever they want to use without SQLx needing to be specifically aware of it.\n    * The `Executor` impls for `Transaction` and `PoolConnection` have been deleted because they cannot exist in the new crate architecture without rewriting the `Executor` trait entirely.\n        * To fix this breakage, simply add a dereference where an `impl Executor` is expected, as they both dereference to the inner connection type which will still implement it:\n            * `&mut transaction` -> `&mut *transaction`\n            * `&mut connection` -> `&mut *connection`\n        * These cannot be blanket impls as it triggers an overflow in the compiler due to the lack of lazy normalization, and\n          the driver crates cannot provide their own impls due to the orphan rule.\n        * We're expecting to do another major refactor of traits to incorporate generic associated types (GAT).\n          This will mean another major release of SQLx but ideally most API usage will not need to change significantly, if at all.\n    * The fields of `Migrator` are now `#[doc(hidden)]` and semver-exempt; they weren't meant to be public.\n    * The `offline` feature has been removed from the `sqlx` facade crate and is enabled unconditionally as most users are expected to have enabled it anyway and disabling it doesn't seem to appreciably affect compile times.\n    * The `decimal` feature has been renamed to `rust_decimal` to match the crate it actually provides integrations for.\n    * `AnyDriver` and `AnyConnection` now require either `sqlx::any::install_drivers()` or `sqlx::any::install_default_drivers()` to be called at some point during the process' lifetime before the first connection is made, as the set of possible drivers is now determined at runtime. This was determined to be the least painful way to provide knowledge of database drivers to `Any` without them being hardcoded.\n    * The `AnyEncode` trait has been removed.\n* [[#2109]]: feat: better database errors [[@saiintbrisson]]\n* [[#2094]]: Update libsqlite3-sys to 0.25.1 [[@penberg]]\n  * Alongside this upgrade, we are now considering the linkage to `libsqlite3-sys` to be **semver-exempt**,\n    and we reserve the right to upgrade it as necessary. If you are using `libsqlite3-sys` directly or a crate that\n    links it such as `rusqlite`, you should pin the versions of both crates to avoid breakages from `cargo update`:\n```toml\n[dependencies]\nsqlx = { version = \"=0.7.0\", features = [\"sqlite\"] }\nrusqlite = \"=0.29.0\"\n```\n* [[#2132]]: fix: use owned Builder pattern for ConnectOptions [[@ar3s3ru]]\n* [[#2253]]: Sqlite describe fixes [[@tyrelr]]\n* [[#2285]]: `time`: Assume UTC when decoding a DATETIME column in sqlite [[@nstinus]]\n* [[#2363]]: [offline] Change prepare to one-file-per-query [[@cycraig]]\n* [[#2387]]: PATCH: bump libsqlite3-sys to patched version [[@grantkee]]\n* [[#2409]]: fix(#2407): respect the HaltIfNull opcode when determining nullability [[@arlyon]]\n* [[#2459]]: limit the number of instructions that can be evaluated [[@tyrelr]]\n* [[#2467]]: Add and improve sqlite describe performance benchmarks [[@tyrelr]]\n* [[#2491]]: sqlite date macro support [[@Arcayr]]\n    * Changes `OffsetDateTime` to be the first type used when deserializing a `timestamp` type.\n* [[#2496]]: Bump to libsqlite3-sys 0.26 [[@mdecimus]]\n* [[#2508]]: Sqlite analytical [[@tyrelr]]\n\n\n### Added\n* [[#1850]]: Add client SSL authentication using key-file for Postgres, MySQL and MariaDB [[@ThibsG]]\n* [[#2088]]: feat: Add set_connect_options method to Pool [[@moatra]]\n* [[#2113]]: Expose PoolOptions for reading [[@FSMaxB]]\n* [[#2115]]: Allow using complex types in `try_from` when deriving `FromRow` [[@95ulisse]]\n* [[#2116]]: [SQLite] Add option to execute `PRAGMA optimize;` on close of a connection [[@miles170]]\n* [[#2189]]: Added regexp support in sqlite [[@VictorKoenders]]\n* [[#2224]]: Add From impls for Json [[@dbeckwith]]\n* [[#2256]]: add progress handler support to sqlite [[@nbaztec]]\n* [[#2366]]: Allow ignoring attributes for deriving FromRow [[@grgi]]\n* [[#2369]]: new type support in query_as [[@0xdeafbeef]]\n* [[#2379]]: feat: add `Connection::shrink_buffers`, `PoolConnection::close` [[@abonander]]\n* [[#2400]]: fix(docs): example of `sqlx_macros_unstable` in config.toml [[@df51d]]\n* [[#2469]]: Add Simple format for Uuid for MySQL & SQLite. [[@MidasLamb]]\n* [[#2483]]: chore: add deprecation notice for type ascription use [[@saiintbrisson]]\n* [[#2506]]: add args to query builder (#2494) [[@cemoktra]]\n* [[#2554]]: Impl `AsMut` for advisory lock types (#2520) [[@alilleybrinker]]\n* [[#2559]]: Add CLI autocompletion using clap_complete [[@titaniumtraveler]]\n\n\n### Changed\n* [[#2185]]: Initial work to switch to `tracing` [[@CosmicHorrorDev]]\n* [[#2193]]: Start testing on Postgres 15 and drop Postgres 10 [[@paolobarbolini]]\n    * We reserve the right to drop support for end-of-lifed database versions [as discussed in our FAQ][faq-db-version].\n* [[#2213]]: Use `let else` statements in favor of macro [[@OverHash]]\n* [[#2365]]: Update dependencies [[@paolobarbolini]]\n* [[#2371]]: Disable rustls crate logging feature by default up to date [[@sergeiivankov]]\n* [[#2373]]: chore: Use tracing's fields to get structured logs [[@jaysonsantos]]\n* [[#2393]]: Lower default logging level for statements to Debug [[@bnoctis]]\n* [[#2445]]: Traverse symlinks when resolving migrations [[@tgeoghegan]]\n* [[#2485]]: chore(sqlx-postgres): replace `dirs` with `home` & `etcetera` [[@utkarshgupta137]]\n* [[#2515]]: Bump mac_address to 1.1.5 [[@repnop]]\n* [[#2440]]: Update rustls to 0.21, webpki-roots to 0.23 [[@SergioBenitez]]\n* [[#2563]]: Update rsa to 0.9 [[@paolobarbolini]]\n* [[#2564]]: Update bitflags to v2 [[@paolobarbolini]]\n* [[#2565]]: Bump indexmap and ahash [[@paolobarbolini]]\n* [[#2574]]: doc: make it clear that `ConnectOptions` types impl `FromStr` [[@abonander]]\n\n### Fixed\n* [[#2098]]: Fix sqlite compilation [[@cycraig]]\n* [[#2120]]: fix logical merge conflict [[@tyrelr]]\n* [[#2133]]: Postgres OID resolution query does not take into account current `search_path` [[@95ulisse]]\n* [[#2156]]: Fixed typo. [[@cdbfoster]]\n* [[#2179]]: fix: ensures recover from fail with PgCopyIn [[@andyquinterom]]\n* [[#2200]]: Run CI on *-dev branch [[@joehillen]]\n* [[#2222]]: Add context to confusing sqlx prepare parse error [[@laundmo]]\n* [[#2271]]: feat: support calling Postgres procedures with the macros [[@bgeron]]\n* [[#2282]]: Don't run EXPLAIN nullability analysis on Materialize [[@benesch]]\n* [[#2319]]: Set whoami default-features to false [[@thedodd]]\n* [[#2352]]: Preparing 0.7.0-alpha.1 release [[@abonander]]\n* [[#2355]]: Fixed the example code for `sqlx::test` [[@kenkoooo]]\n* [[#2367]]: Fix sqlx-cli create, drop, migrate [[@cycraig]]\n* [[#2376]]: fix(pool): close when last handle is dropped, extra check in `try_acquire` [[@abonander]]\n* [[#2378]]: Fix README build badge [[@dbrgn]]\n* [[#2398]]: fix(prepare): store temporary query files inside the workspace [[@aschey]]\n* [[#2402]]: fix: drop old time 0.1.44 dep [[@codahale]]\n* [[#2413]]: fix(macros-core): use of undeclared `tracked_path` [[@df51d]]\n* [[#2420]]: Enable runtime-tokio feature of sqlx when building sqlx-cli [[@paolobarbolini]]\n* [[#2453]]: in README.md, correct spelling and grammar [[@vizvasrj]]\n* [[#2454]]: fix: ensure fresh test db's aren't accidentally deleted by do_cleanup [[@phlip9]]\n* [[#2507]]: Exposing the Oid of PostgreSQL types [[@Razican]]\n* [[#2519]]: Use ::std::result::Result::Ok in output.rs [[@southball]]\n* [[#2569]]: Fix broken links to mysql error documentation [[@titaniumtraveler]]\n* [[#2570]]: Add a newline to the generated JSON files [[@nyurik]]\n* [[#2572]]: Do not panic when `PrepareOk` fails to decode [[@stepantubanov]]\n* [[#2573]]: fix(sqlite) Do not drop notify mutex guard until after condvar is triggered [[@andrewwhitehead]]\n\n[sqlx-pro]: https://github.com/launchbadge/sqlx/discussions/1616\n\n[faq-db-version]: https://github.com/launchbadge/sqlx/blob/main/FAQ.md#what-database-versions-does-sqlx-support\n\n[#1850]: https://github.com/launchbadge/sqlx/pull/1850\n[#1946]: https://github.com/launchbadge/sqlx/pull/1946\n[#1960]: https://github.com/launchbadge/sqlx/pull/1960\n[#1984]: https://github.com/launchbadge/sqlx/pull/1984\n[#2039]: https://github.com/launchbadge/sqlx/pull/2039\n[#2088]: https://github.com/launchbadge/sqlx/pull/2088\n[#2092]: https://github.com/launchbadge/sqlx/pull/2092\n[#2094]: https://github.com/launchbadge/sqlx/pull/2094\n[#2098]: https://github.com/launchbadge/sqlx/pull/2098\n[#2109]: https://github.com/launchbadge/sqlx/pull/2109\n[#2113]: https://github.com/launchbadge/sqlx/pull/2113\n[#2115]: https://github.com/launchbadge/sqlx/pull/2115\n[#2116]: https://github.com/launchbadge/sqlx/pull/2116\n[#2120]: https://github.com/launchbadge/sqlx/pull/2120\n[#2132]: https://github.com/launchbadge/sqlx/pull/2132\n[#2133]: https://github.com/launchbadge/sqlx/pull/2133\n[#2156]: https://github.com/launchbadge/sqlx/pull/2156\n[#2179]: https://github.com/launchbadge/sqlx/pull/2179\n[#2185]: https://github.com/launchbadge/sqlx/pull/2185\n[#2189]: https://github.com/launchbadge/sqlx/pull/2189\n[#2193]: https://github.com/launchbadge/sqlx/pull/2193\n[#2200]: https://github.com/launchbadge/sqlx/pull/2200\n[#2213]: https://github.com/launchbadge/sqlx/pull/2213\n[#2222]: https://github.com/launchbadge/sqlx/pull/2222\n[#2224]: https://github.com/launchbadge/sqlx/pull/2224\n[#2253]: https://github.com/launchbadge/sqlx/pull/2253\n[#2256]: https://github.com/launchbadge/sqlx/pull/2256\n[#2271]: https://github.com/launchbadge/sqlx/pull/2271\n[#2282]: https://github.com/launchbadge/sqlx/pull/2282\n[#2285]: https://github.com/launchbadge/sqlx/pull/2285\n[#2319]: https://github.com/launchbadge/sqlx/pull/2319\n[#2352]: https://github.com/launchbadge/sqlx/pull/2352\n[#2355]: https://github.com/launchbadge/sqlx/pull/2355\n[#2363]: https://github.com/launchbadge/sqlx/pull/2363\n[#2365]: https://github.com/launchbadge/sqlx/pull/2365\n[#2366]: https://github.com/launchbadge/sqlx/pull/2366\n[#2367]: https://github.com/launchbadge/sqlx/pull/2367\n[#2369]: https://github.com/launchbadge/sqlx/pull/2369\n[#2371]: https://github.com/launchbadge/sqlx/pull/2371\n[#2373]: https://github.com/launchbadge/sqlx/pull/2373\n[#2376]: https://github.com/launchbadge/sqlx/pull/2376\n[#2378]: https://github.com/launchbadge/sqlx/pull/2378\n[#2379]: https://github.com/launchbadge/sqlx/pull/2379\n[#2387]: https://github.com/launchbadge/sqlx/pull/2387\n[#2393]: https://github.com/launchbadge/sqlx/pull/2393\n[#2398]: https://github.com/launchbadge/sqlx/pull/2398\n[#2400]: https://github.com/launchbadge/sqlx/pull/2400\n[#2402]: https://github.com/launchbadge/sqlx/pull/2402\n[#2408]: https://github.com/launchbadge/sqlx/pull/2408\n[#2409]: https://github.com/launchbadge/sqlx/pull/2409\n[#2413]: https://github.com/launchbadge/sqlx/pull/2413\n[#2420]: https://github.com/launchbadge/sqlx/pull/2420\n[#2440]: https://github.com/launchbadge/sqlx/pull/2440\n[#2445]: https://github.com/launchbadge/sqlx/pull/2445\n[#2453]: https://github.com/launchbadge/sqlx/pull/2453\n[#2454]: https://github.com/launchbadge/sqlx/pull/2454\n[#2459]: https://github.com/launchbadge/sqlx/pull/2459\n[#2467]: https://github.com/launchbadge/sqlx/pull/2467\n[#2469]: https://github.com/launchbadge/sqlx/pull/2469\n[#2483]: https://github.com/launchbadge/sqlx/pull/2483\n[#2485]: https://github.com/launchbadge/sqlx/pull/2485\n[#2491]: https://github.com/launchbadge/sqlx/pull/2491\n[#2496]: https://github.com/launchbadge/sqlx/pull/2496\n[#2506]: https://github.com/launchbadge/sqlx/pull/2506\n[#2507]: https://github.com/launchbadge/sqlx/pull/2507\n[#2508]: https://github.com/launchbadge/sqlx/pull/2508\n[#2515]: https://github.com/launchbadge/sqlx/pull/2515\n[#2519]: https://github.com/launchbadge/sqlx/pull/2519\n[#2554]: https://github.com/launchbadge/sqlx/pull/2554\n[#2559]: https://github.com/launchbadge/sqlx/pull/2559\n[#2563]: https://github.com/launchbadge/sqlx/pull/2563\n[#2564]: https://github.com/launchbadge/sqlx/pull/2564\n[#2565]: https://github.com/launchbadge/sqlx/pull/2565\n[#2569]: https://github.com/launchbadge/sqlx/pull/2569\n[#2570]: https://github.com/launchbadge/sqlx/pull/2570\n[#2572]: https://github.com/launchbadge/sqlx/pull/2572\n[#2573]: https://github.com/launchbadge/sqlx/pull/2573\n[#2574]: https://github.com/launchbadge/sqlx/pull/2574\n\n## 0.6.3 - 2023-03-21\n\nThis is a hotfix to address the breakage caused by transitive dependencies upgrading to `syn = \"2\"`.\n\nWe set `default-features = false` for our dependency on `syn = \"1\"` to be good crates.io citizens, \nbut failed to enable the features we actually used, which went undetected because we transitively depended on\n`syn` with the default features enabled through other crates, \nand so they were also on for us because features are additive.\n\nWhen those other dependencies upgraded to `syn = \"2\"` it was no longer enabling those features for us, \nand so compilation broke for projects that don't also depend on `syn = \"1\"`, transitively or otherwise.\n\nThere is no PR for this fix as there was no longer a dedicated development branch for `0.6`, \nbut discussion can be found in [issue #2418].\n\nAs of this release, the `0.7` release is in alpha and so development is no longer occurring against `0.6`.\nThis fix will be forward-ported to `0.7`.\n\n[issue #2418]: https://github.com/launchbadge/sqlx/issues/2418\n\n## 0.6.2 - 2022-09-14\n\n[25 pull requests][0.6.2-prs] were merged this release cycle.\n\n### Added\n* [[#1081]]: Add `try_from` attribute for `FromRow` derive [[@zzhengzhuo]]\n    * Exemplifies \"out of sight, out of mind.\" It's surprisingly easy to forget about PRs when they get pushed onto\n      the second page. We'll be sure to clean out the backlog for 0.7.0.\n* [[#2014]]: Support additional SQLCipher options in SQLite driver. [[@szymek156]]\n* [[#2052]]: Add issue templates [[@abonander]]\n* [[#2053]]: Add documentation for `IpAddr` support in Postgres [[@rakshith-ravi]]\n* [[#2062]]: Add extension support for SQLite [[@bradfier]]\n* [[#2063]]: customizable db locking during migration [[@fuzzbuck]]\n\n### Changed\n* [[#2025]]: Bump sqlformat to 2.0 [[@NSMustache]]\n* [[#2056]]: chore: Switch to sha1 crate [[@stoically]]\n* [[#2071]]: Use cargo check consistently in `prepare` [[@cycraig]]\n\n### Fixed\n* [[#1991]]: Ensure migration progress is not lost for Postgres, MySQL and SQLite. [[@crepererum]]\n* [[#2023]]: Fix expansion of `#[sqlx(flatten)]` for `FromRow` derive [[@RustyYato]]\n* [[#2028]]: Use fully qualified path when forwarding to `#[test]` from `#[sqlx::test]` [[@alexander-jackson]]\n* [[#2040]]: Fix typo in `FromRow` docs [[@zlidner]]\n* [[#2046]]: added flag for PIPES_AS_CONCAT connection setting for MySQL to fix #2034 [[@marcustut]]\n* [[#2055]]: Use unlock notify also on `sqlite3_exec`  [[@madadam]]\n* [[#2057]]: Make begin,commit,rollback cancel-safe in sqlite  [[@madadam]]\n* [[#2058]]: fix typo in documentation [[@lovasoa]]\n* [[#2067]]: fix(docs): close code block in query_builder.rs [[@abonander]]\n* [[#2069]]: Fix `prepare` race condition in workspaces [[@cycraig]]\\\n    * NOTE: this changes the directory structure under `target/` that `cargo sqlx prepare` depends on.\n      If you use offline mode in your workflow, please rerun `cargo install sqlx-cli` to upgrade.\n* [[#2072]]: SqliteConnectOptions typo [[@fasterthanlime]]\n* [[#2074]]: fix: mssql uses unsigned for tinyint instead of signed [[@he4d]]\n* [[#2081]]: close unnamed portal after each executed extended query [[@DXist]]\n* [[#2086]]: PgHasArrayType for transparent types fix. [[@Wopple]]\n    * NOTE: this is a breaking change and has been postponed to 0.7.0.\n* [[#2089]]: fix: Remove default chrono dep on time for sqlx-cli [[@TravisWhitehead]]\n* [[#2091]]: Sqlite explain plan log efficiency [[@tyrelr]]\n\n[0.6.2-prs]: https://github.com/launchbadge/sqlx/pulls?q=is%3Apr+is%3Aclosed+merged%3A2022-08-04..2022-09-14+\n\n[#1081]: https://github.com/launchbadge/sqlx/pull/1081\n[#1991]: https://github.com/launchbadge/sqlx/pull/1991\n[#2014]: https://github.com/launchbadge/sqlx/pull/2014\n[#2023]: https://github.com/launchbadge/sqlx/pull/2023\n[#2025]: https://github.com/launchbadge/sqlx/pull/2025\n[#2028]: https://github.com/launchbadge/sqlx/pull/2028\n[#2040]: https://github.com/launchbadge/sqlx/pull/2040\n[#2046]: https://github.com/launchbadge/sqlx/pull/2046\n[#2052]: https://github.com/launchbadge/sqlx/pull/2052\n[#2053]: https://github.com/launchbadge/sqlx/pull/2053\n[#2055]: https://github.com/launchbadge/sqlx/pull/2055\n[#2056]: https://github.com/launchbadge/sqlx/pull/2056\n[#2057]: https://github.com/launchbadge/sqlx/pull/2057\n[#2058]: https://github.com/launchbadge/sqlx/pull/2058\n[#2062]: https://github.com/launchbadge/sqlx/pull/2062\n[#2063]: https://github.com/launchbadge/sqlx/pull/2063\n[#2067]: https://github.com/launchbadge/sqlx/pull/2067\n[#2069]: https://github.com/launchbadge/sqlx/pull/2069\n[#2071]: https://github.com/launchbadge/sqlx/pull/2071\n[#2072]: https://github.com/launchbadge/sqlx/pull/2072\n[#2074]: https://github.com/launchbadge/sqlx/pull/2074\n[#2081]: https://github.com/launchbadge/sqlx/pull/2081\n[#2086]: https://github.com/launchbadge/sqlx/pull/2086\n[#2089]: https://github.com/launchbadge/sqlx/pull/2089\n[#2091]: https://github.com/launchbadge/sqlx/pull/2091\n\n## 0.6.1 - 2022-08-02\n\n[33 pull requests][0.6.1-prs] were merged this release cycle.\n\n### Added\n* [[#1495]]: Add example for manual implementation of the `FromRow` trait [[@Erik1000]]\n* [[#1822]]: (Postgres) Add support for `std::net::IpAddr` [[@meh]]\n    * Decoding returns an error if the `INET` value in Postgres is a prefix and not a full address\n      (`/32` for IPv4, `/128` for IPv6).\n* [[#1865]]: Add SQLite support for the `time` crate [[@johnbcodes]]\n* [[#1902]]: Add an example of how to use `QueryBuilder::separated()` [[@sbeckeriv]]\n* [[#1917]]: Added docs for `sqlx::types::Json` [[@jayy-lmao]]\n* [[#1919]]: Implement `Clone` for `PoolOptions` [[@Thomasdezeeuw]]\n* [[#1953]]: Support Rust arrays in Postgres [[@e00E]]\n* [[#1954]]: Add `push_tuples` for `QueryBuilder` [[@0xdeafbeef]]\n* [[#1959]]: Support `#[sqlx(flatten)]` attribute in `FromRow` [[@TheoOiry]]\n* [[#1967]]: Add example with external query files [[@JoeyMckenzie]]\n* [[#1985]]: Add `query_builder::Separated::push_bind_unseparated()` [[@0xdeafbeef]]\n* [[#2001]]: Implement `#[sqlx::test]` for general use\n    * Includes automatic database management, migration and fixture application.\n    * Drops support for end-of-lifed database versions, see PR for details.\n* [[#2005]]: `QueryBuilder` improvements [[@abonander]]\n    * Raw SQL getters, new method to build `QueryAs` instead of `Query`.\n* [[#2013]]: (SQLite) Allow VFS to be set as URL query parameter [[@liningpan]] \n\n### Changed\n* [[#1679]]: refactor: alias actix-* features to their equivalent tokio-* features [[@robjtede]]\n* [[#1906]]: replaced all uses of \"uri\" to \"url\" [[@RomainStorai]]\n* [[#1965]]: SQLite improvements [[@abonander]]\n* [[#1977]]: Docs: clarify relationship between `query_as!()` and `FromRow` [[@abonander]]\n* [[#2003]]: Replace `dotenv` with `dotenvy` [[@abonander]]\n\n### Fixed\n* [[#1802]]: Try avoiding a full clean in `cargo sqlx prepare --merged` [[@LovecraftianHorror]]\n* [[#1848]]: Fix type info access in `Any` database driver [[@raviqqe]]\n* [[#1910]]: Set `CARGO_TARGET_DIR` when compiling queries [[@sedrik]]\n* [[#1915]]: Pool: fix panic when using callbacks [[@abonander]]\n* [[#1930]]: Don't cache SQLite connection for macros [[@LovecraftianHorror]]\n* [[#1948]]: Fix panic in Postgres `BYTEA` decode [[@e00E]]\n* [[#1955]]: Fix typo in FAQ [[@kenkoooo]]\n* [[#1968]]: (Postgres) don't panic if `S` or `V` notice fields are not UTF-8 [[@abonander]]\n* [[#1969]]: Fix sqlx-cli build [[@ivan]]\n* [[#1974]]: Use the `rust-cache` action for CI [[@abonander]]\n* [[#1988]]: Agree on a single default runtime for the whole workspace [[@crepererum]]\n* [[#1989]]: Fix panics in `PgListener` [[@crepererum]]\n* [[#1990]]: Switch `master` to `main` in docs [[@crepererum]]\n    * The change had already been made in the repo, the docs were out of date.\n* [[#1993]]: Update versions in quickstart examples in README [[@UramnOIL]]\n\n[0.6.1-prs]: https://github.com/launchbadge/sqlx/pulls?page=1&q=is%3Apr+is%3Aclosed+merged%3A2022-06-17..2022-08-02\n\n[#1906]: https://github.com/launchbadge/sqlx/pull/1906\n[#1495]: https://github.com/launchbadge/sqlx/pull/1495\n[#1679]: https://github.com/launchbadge/sqlx/pull/1679\n[#1802]: https://github.com/launchbadge/sqlx/pull/1802\n[#1822]: https://github.com/launchbadge/sqlx/pull/1822\n[#1848]: https://github.com/launchbadge/sqlx/pull/1848\n[#1865]: https://github.com/launchbadge/sqlx/pull/1865\n[#1902]: https://github.com/launchbadge/sqlx/pull/1902\n[#1910]: https://github.com/launchbadge/sqlx/pull/1910\n[#1915]: https://github.com/launchbadge/sqlx/pull/1915\n[#1917]: https://github.com/launchbadge/sqlx/pull/1917\n[#1919]: https://github.com/launchbadge/sqlx/pull/1919\n[#1930]: https://github.com/launchbadge/sqlx/pull/1930\n[#1948]: https://github.com/launchbadge/sqlx/pull/1948\n[#1953]: https://github.com/launchbadge/sqlx/pull/1953\n[#1954]: https://github.com/launchbadge/sqlx/pull/1954\n[#1955]: https://github.com/launchbadge/sqlx/pull/1955\n[#1959]: https://github.com/launchbadge/sqlx/pull/1959\n[#1965]: https://github.com/launchbadge/sqlx/pull/1965\n[#1967]: https://github.com/launchbadge/sqlx/pull/1967\n[#1968]: https://github.com/launchbadge/sqlx/pull/1968\n[#1969]: https://github.com/launchbadge/sqlx/pull/1969\n[#1974]: https://github.com/launchbadge/sqlx/pull/1974\n[#1977]: https://github.com/launchbadge/sqlx/pull/1977\n[#1985]: https://github.com/launchbadge/sqlx/pull/1985\n[#1988]: https://github.com/launchbadge/sqlx/pull/1988\n[#1989]: https://github.com/launchbadge/sqlx/pull/1989\n[#1990]: https://github.com/launchbadge/sqlx/pull/1990\n[#1993]: https://github.com/launchbadge/sqlx/pull/1993\n[#2001]: https://github.com/launchbadge/sqlx/pull/2001\n[#2003]: https://github.com/launchbadge/sqlx/pull/2003\n[#2005]: https://github.com/launchbadge/sqlx/pull/2005\n[#2013]: https://github.com/launchbadge/sqlx/pull/2013\n\n## 0.6.0 - 2022-06-16\n\nThis release marks the end of the 0.5.x series of releases and contains a number of breaking changes,\nmainly to do with backwards-incompatible dependency upgrades. \n\nAs we foresee many more of these in the future, we [surveyed the community] on how to handle this;\nthe consensus appears to be \"just release breaking changes more often.\" \n\nAs such, we expect the 0.6.x release series to be a shorter one.\n\n[39 pull requests(!)][0.6.0-prs] (not counting \"prepare 0.5.12 release\", of course) were merged this release cycle.\n\n### Breaking\n* [[#1384]]: (Postgres) Move `server_version_num` from trait to inherent impl [[@AtkinsChang]]\n* [[#1426]]: Bump `ipnetwork` to 0.19 [[@paolobarbolini]]\n* [[#1455]]: Upgrade `time` to 0.3 [[@paolobarbolini]]\n* [[#1505]]: Upgrade `rustls` to 0.20 [[@paolobarbolini]]\n    * Fortunately, future upgrades should not be breaking as `webpki` is no longer exposed in the API.\n* [[#1529]]: Upgrade `bigdecimal` to 0.3 [[@e00E]]\n* [[#1602]]: postgres: use `Oid` everywhere instead of `u32` [[@paolobarbolini]]\n    * This drops the `Type`, `Decode`, `Encode` impls for `u32` for Postgres as it was misleading.\n      Postgres doesn't support unsigned ints without using an extension. These impls were decoding Postgres `OID`s\n      as bare `u32`s without any context (and trying to bind a `u32` to a query would produce an `OID` value in SQL).\n      This changes that to use a newtype instead, for clarity.\n* [[#1612]]: Make all `ConnectOptions` types cloneable [[@05storm26]]\n* [[#1618]]: SQLite `chrono::DateTime<FixedOffset>` timezone fix [[@05storm26]]\n    * `DateTime<FixedOffset>` will be stored in SQLite with the correct timezone instead of always in UTC.\n      This was flagged as a \"potentially breaking change\" since it changes how dates are sent to SQLite.\n* [[#1733]]: Update `git2` to 0.14 [[@joshtriplett]]\n* [[#1734]]: Make `PgLTree::push()` infallible and take `PgLTreeLabel` directly [[@sebpuetz]]\n* [[#1785]]: Fix Rust type for SQLite `REAL` [[@pruthvikar]]\n    * Makes the macros always map a `REAL` column to `f64` instead of `f32` as SQLite uses **only** 64-bit floats.\n* [[#1816]]: Improve SQLite support for sub-queries and CTEs [[@tyrelr]]\n    * This likely will change the generated code for some invocations `sqlx::query!()` with SQLite.\n* [[#1821]]: Update `uuid` crate to v1 [[@paolobarbolini]]\n* [[#1901]]: Pool fixes and breaking changes [[@abonander]]\n    * Renamed `PoolOptions::connect_timeout` to `acquire_timeout` for clarity.\n    * Changed the expected signatures for `PoolOptions::after_connect`, `before_acquire`, `after_release`\n    * Changed the signature for `Pool::close()` slightly\n        * Now eagerly starts the pool closing, `.await`ing is only necessary if you want to ensure a graceful shutdown.\n    * Deleted `PoolConnection::release()` which was previously deprecated in favor of `PoolConnection::detach()`.\n    * Fixed connections getting leaked even when calling `.close()`.\n* [[#1748]]: Derive `PgHasArrayType` for `#[sqlx(transparent)]` types [[@carols10cents]]\n    * This change was released with 0.5.12 but [we didn't realize it was a breaking change] at the time.  \n      It was reverted in 0.5.13 and postponed until this release.\n\n### Added\n* [[#1843]]: Expose some useful methods on `PgValueRef` [[@mfreeborn]]\n* [[#1889]]: SQLx-CLI: add `--connect-timeout` [[@abonander]]\n    * Adds a default 10 second connection timeout to all commands.\n* [[#1890]]: Added test for mssql LoginAck [[@walf443]]\n* [[#1891]]: Added test for mssql ProtocolInfo [[@walf443]]\n* [[#1892]]: Added test for mssql ReturnValue [[@walf443]]\n* [[#1895]]: Add support for `i16` to `Any` driver [[@EthanYuan]]\n* [[#1897]]: Expose `ConnectOptions` and `PoolOptions` on `Pool` and database name on `PgConnectOptions` [[@Nukesor]]\n\n### Changed\n* [[#1782]]: Reuse a cached DB connection instead of always opening a new one for `sqlx-macros` [[@LovecraftianHorror]]\n* [[#1807]]: Bump remaining dependencies [[@paolobarbolini]]\n* [[#1808]]: Update to edition 2021 [[@paolobarbolini]]\n    * Note that while SQLx [does not officially track an MSRV] and only officially supports the latest stable Rust, \n      this effectively places a lower bound of 1.56.0 on the range of versions it may work with.\n* [[#1823]]: (sqlx-macros) Ignore deps when getting metadata for workspace root [[@LovecraftianHorror]]\n* [[#1831]]: Update `crc` to 3.0 [[@djc]]\n* [[#1887]]: query_as: don't stop stream after decoding error [[@lovasoa]]\n\n### Fixed\n* [[#1814]]: SQLx-cli README: move `Usage` to the same level as `Install` [[@tobymurray]]\n* [[#1815]]: SQLx-cli README: reword \"building in offline mode\" [[@tobymurray]]\n* [[#1818]]: Trim `[]` from host string before passing to TcpStream [[@smonv]]\n    * This fixes handling of database URLs with IPv6 hosts.\n* [[#1842]]: Fix usage of `serde_json` in macros [[@mfreeborn]]\n* [[#1855]]: Postgres: fix panics on unknown type OID when decoding [[@demurgos]] \n* [[#1856]]: MySQL: support COLLATE_UTF8MB4_0900_AI_CI [[@scottwey]]\n    * Fixes the MySQL driver thinking text columns are bytestring columns when querying against a Planetscale DB.\n* [[#1861]]: MySQL: avoid panic when streaming packets are empty [[@e-rhodes]]\n* [[#1863]]: Fix nullability check for inner joins in Postgres [[@OskarPersson]]\n* [[#1881]]: Fix `field is never read` warnings on Postgres test [[@walf443]]\n* [[#1882]]: Fix `unused result must be used` warnings [[@walf443]]\n* [[#1888]]: Fix migration checksum comparison during `sqlx migrate info` [[@mdtusz]]\n* [[#1894]]: Fix typos [[@kianmeng]]\n\n[surveyed the community]: https://github.com/launchbadge/sqlx/issues/1796\n[0.6.0-prs]: https://github.com/launchbadge/sqlx/pulls?page=2&q=is%3Apr+is%3Amerged+merged%3A2022-04-14..2022-06-16\n[does not officially track an MSRV]: /FAQ.md#what-versions-of-rust-does-sqlx-support-what-is-sqlxs-msrv\n[we didn't realize it was a breaking change]: https://github.com/launchbadge/sqlx/pull/1800#issuecomment-1099898932\n\n[#1384]: https://github.com/launchbadge/sqlx/pull/1384\n[#1426]: https://github.com/launchbadge/sqlx/pull/1426\n[#1455]: https://github.com/launchbadge/sqlx/pull/1455\n[#1505]: https://github.com/launchbadge/sqlx/pull/1505\n[#1529]: https://github.com/launchbadge/sqlx/pull/1529\n[#1602]: https://github.com/launchbadge/sqlx/pull/1602\n[#1612]: https://github.com/launchbadge/sqlx/pull/1612\n[#1618]: https://github.com/launchbadge/sqlx/pull/1618\n[#1733]: https://github.com/launchbadge/sqlx/pull/1733\n[#1734]: https://github.com/launchbadge/sqlx/pull/1734\n[#1782]: https://github.com/launchbadge/sqlx/pull/1782\n[#1785]: https://github.com/launchbadge/sqlx/pull/1785\n[#1807]: https://github.com/launchbadge/sqlx/pull/1807\n[#1808]: https://github.com/launchbadge/sqlx/pull/1808\n[#1814]: https://github.com/launchbadge/sqlx/pull/1814\n[#1815]: https://github.com/launchbadge/sqlx/pull/1815\n[#1816]: https://github.com/launchbadge/sqlx/pull/1816\n[#1818]: https://github.com/launchbadge/sqlx/pull/1818\n[#1821]: https://github.com/launchbadge/sqlx/pull/1821\n[#1823]: https://github.com/launchbadge/sqlx/pull/1823\n[#1831]: https://github.com/launchbadge/sqlx/pull/1831\n[#1842]: https://github.com/launchbadge/sqlx/pull/1842\n[#1843]: https://github.com/launchbadge/sqlx/pull/1843\n[#1855]: https://github.com/launchbadge/sqlx/pull/1855\n[#1856]: https://github.com/launchbadge/sqlx/pull/1856\n[#1861]: https://github.com/launchbadge/sqlx/pull/1861\n[#1863]: https://github.com/launchbadge/sqlx/pull/1863\n[#1881]: https://github.com/launchbadge/sqlx/pull/1881\n[#1882]: https://github.com/launchbadge/sqlx/pull/1882\n[#1887]: https://github.com/launchbadge/sqlx/pull/1887\n[#1888]: https://github.com/launchbadge/sqlx/pull/1888\n[#1889]: https://github.com/launchbadge/sqlx/pull/1889\n[#1890]: https://github.com/launchbadge/sqlx/pull/1890\n[#1891]: https://github.com/launchbadge/sqlx/pull/1891\n[#1892]: https://github.com/launchbadge/sqlx/pull/1892\n[#1894]: https://github.com/launchbadge/sqlx/pull/1894\n[#1895]: https://github.com/launchbadge/sqlx/pull/1895\n[#1897]: https://github.com/launchbadge/sqlx/pull/1897\n[#1901]: https://github.com/launchbadge/sqlx/pull/1901\n\n## 0.5.13 - 2022-04-15\n\nThis is a hotfix that reverts [#1748] as that was an accidental breaking change:  \nthe generated `PgHasArrayType` impl conflicts with manual impls of the trait.  \nThis change will have to wait for 0.6.0.\n\n## 0.5.12 - 2022-04-13 (Yanked; use 0.5.13)\n[27 pull requests][0.5.12-prs] were merged this release cycle.\n\n### Added\n* [[#1641]]: Postgres: Convenient wrapper for advisory locks [[@abonander]]\n* [[#1675]]: Add function to undo migrations [[@jdrouet]]\n* [[#1722]]: Postgres: implement `PgHasArrayType` for `serde_json::{Value, RawValue}` [[@abreis]]\n* [[#1736]]: Derive `Clone` for `MySqlArguments` and `MssqlArguments` [[@0xdeafbeef]]\n* [[#1748]]: Derive `PgHasArrayType` for `#[sqlx(transparent)]` types [[@carols10cents]]\n* [[#1754]]: Include affected rows alongside returned rows in query logging [[@david-mcgillicuddy-moixa]]\n* [[#1757]]: Implement `Type` for `Cow<str>` for MySQL, MSSQL and SQLite [[@ipetkov]]\n* [[#1769]]: sqlx-cli: add `--source` to migration subcommands [[@pedromfedricci]]\n* [[#1774]]: Postgres: make `extra_float_digits` settable [[@abonander]]\n    * Can be set to `None` for Postgres or third-party database servers that don't support the option.\n* [[#1776]]: Implement close-event notification for Pool [[@abonander]]\n    * Also fixes `PgListener` preventing `Pool::close()` from resolving.\n* [[#1780]]: Implement query builder [[@crajcan]]\n    * See also [[#1790]]: Document and expand query builder [[@abonander]]\n* [[#1781]]: Postgres: support `NUMERIC[]` using `decimal` feature [[@tm-drtina]]\n* [[#1784]]: SQLite: add `FromStr`, `Copy`, `PartialEq`, `Eq` impls for options enums [[@andrewwhitehead]]\n\n### Changed\n* [[#1625]]: Update RustCrypto crates [[@paolobarbolini]]\n* [[#1725]]: Update `heck` to 0.4 [[@paolobarbolini]]\n* [[#1738]]: Update `regex` [[@Dylan-DPC]]\n* [[#1763]]: SQLite: update `libsqlite3-sys` [[@espindola]]\n\n\n### Fixed\n* [[#1719]]: Fix a link in `query!()` docs [[@vbmade2000]]\n* [[#1731]]: Postgres: fix option passing logic [[@liushuyu]]\n* [[#1735]]: sqlx-cli: pass `DATABASE_URL` to command spawned in `prepare` [[@LovecraftianHorror]]\n* [[#1741]]: Postgres: fix typo in `TSTZRANGE` [[@mgrachev]]\n* [[#1761]]: Fix link from `QueryAs` to `query_as()` in docs [[@mgrachev]]\n* [[#1786]]: MySQL: silence compile warnings for unused fields [[@andrewwhitehead]]\n* [[#1789]]: SQLite: fix left-joins breaking `query!()` macros [[@tyrelr]]\n* [[#1791]]: Postgres: fix newline parsing of `.pgpass` files [[@SebastienGllmt]]\n* [[#1799]]: `PoolConnection`: don't leak connection permit if drop task fails to run [[@abonander]]\n\n[#1625]: https://github.com/launchbadge/sqlx/pull/1625\n[#1641]: https://github.com/launchbadge/sqlx/pull/1641\n[#1675]: https://github.com/launchbadge/sqlx/pull/1675\n[#1719]: https://github.com/launchbadge/sqlx/pull/1719\n[#1722]: https://github.com/launchbadge/sqlx/pull/1722\n[#1725]: https://github.com/launchbadge/sqlx/pull/1725\n[#1731]: https://github.com/launchbadge/sqlx/pull/1731\n[#1735]: https://github.com/launchbadge/sqlx/pull/1735\n[#1736]: https://github.com/launchbadge/sqlx/pull/1736\n[#1738]: https://github.com/launchbadge/sqlx/pull/1738\n[#1741]: https://github.com/launchbadge/sqlx/pull/1741\n[#1748]: https://github.com/launchbadge/sqlx/pull/1748\n[#1754]: https://github.com/launchbadge/sqlx/pull/1754\n[#1757]: https://github.com/launchbadge/sqlx/pull/1757\n[#1761]: https://github.com/launchbadge/sqlx/pull/1761\n[#1763]: https://github.com/launchbadge/sqlx/pull/1763\n[#1769]: https://github.com/launchbadge/sqlx/pull/1769\n[#1774]: https://github.com/launchbadge/sqlx/pull/1774\n[#1776]: https://github.com/launchbadge/sqlx/pull/1776\n[#1780]: https://github.com/launchbadge/sqlx/pull/1780\n[#1781]: https://github.com/launchbadge/sqlx/pull/1781\n[#1784]: https://github.com/launchbadge/sqlx/pull/1784\n[#1786]: https://github.com/launchbadge/sqlx/pull/1786\n[#1789]: https://github.com/launchbadge/sqlx/pull/1789\n[#1790]: https://github.com/launchbadge/sqlx/pull/1790\n[#1791]: https://github.com/launchbadge/sqlx/pull/1791\n[#1799]: https://github.com/launchbadge/sqlx/pull/1799\n\n[0.5.12-prs]: https://github.com/launchbadge/sqlx/pulls?q=is%3Apr+is%3Amerged+merged%3A2022-02-19..2022-04-13\n\n## 0.5.11 - 2022-02-17\n[20 pull requests][0.5.11-prs] were merged this release cycle.\n\n### Added\n* [[#1610]]: Allow converting `AnyConnectOptions` to a specific `ConnectOptions` [[@05storm26]]\n* [[#1652]]: Implement `From` for `AnyConnection` [[@genusistimelord]]\n* [[#1658]]: Handle `SQLITE_LOCKED` [[@madadam]]\n* [[#1665]]: Document offline mode usage with feature flags [[@sedrik]]\n* [[#1680]]: Show checksum mismatches in `sqlx migrate info` [[@ifn3]]\n* [[#1685]]: Add tip for setting `opt-level` for `sqlx-macros` [[@LovecraftianHorror]]\n* [[#1687]]: Docs: `Acquire` examples and alternative [[@stoically]]\n* [[#1696]]: Postgres: support for `ltree` [[@cemoktra]]\n* [[#1710]]: Postgres: support for `lquery` [[@cemoktra]]\n\n### Changed\n* [[#1605]]: Remove unused dependencies [[@paolobarbolini]]\n* [[#1606]]: Add target context to Postgres `NOTICE` logs [[@dbeckwith]]\n* [[#1684]]: Macros: Cache parsed `sqlx-data.json` instead of reparsing [[@LovecraftianHorror]]\n\n### Fixed\n* [[#1608]]: Drop worker shared state in shutdown (SQLite) [[@andrewwhitehead]]\n* [[#1619]]: Docs(macros): remove sentences banning usage of `as _` [[@k-jun]]\n* [[#1626]]: Simplify `cargo-sqlx` command-line definition [[@tranzystorek-io]]\n* [[#1636]]: Fix and extend Postgres transaction example [[@taladar]]\n* [[#1657]]: Fix typo in macro docs [[@p9s]]\n* [[#1661]]: Fix binding `Option<T>` for `Any` driver [[@ArGGu]]\n* [[#1667]]: MySQL: Avoid panicking if packet is empty [[@nappa85]]\n* [[#1692]]: Postgres: Fix power calculation when encoding `BigDecimal` into `NUMERIC` [[@VersBinarii]]\n\nAdditionally, we have introduced two mitigations for [the issue of the cyclic dependency on `ahash`][aHash#95]: \n\n* We re-downgraded our version requirement on `indexmap` from `1.7.0` back to `1.6.2` so users can pin it to that\n  version [as recommended in aHash#95][ahash-fix]. \n  * [This was regressed accidentally during a sweeping dependency upgrade before the last release][indexmap-regression],\n    sorry about that.\n* Thanks to the work of [@LovecraftianHorror] in [#1684], we no longer require the `preserve_order` feature of\n  `serde_json` which gives users another place to break the cycle by simply not enabling that feature. \n  * This may introduce extra churn in Git diffs for `sqlx-data.json`, however. If this is an issue for you but \n    the dependency cycle isn't, you can re-enable the `preserve_order` feature:\n  ```toml\n  [dependencies]\n  serde_json = { version = \"1\", features = [\"preserve_order\"] }\n  ```\n\n[aHash#95]: https://github.com/tkaitchuck/aHash/issues/95\n[ahash-fix]: https://github.com/tkaitchuck/aHash/issues/95#issuecomment-874150078\n[indexmap-regression]: https://github.com/launchbadge/sqlx/pull/1603#issuecomment-1010827637\n\n[#1605]: https://github.com/launchbadge/sqlx/pull/1605\n[#1606]: https://github.com/launchbadge/sqlx/pull/1606\n[#1608]: https://github.com/launchbadge/sqlx/pull/1608\n[#1610]: https://github.com/launchbadge/sqlx/pull/1610\n[#1619]: https://github.com/launchbadge/sqlx/pull/1619\n[#1626]: https://github.com/launchbadge/sqlx/pull/1626\n[#1636]: https://github.com/launchbadge/sqlx/pull/1636\n[#1652]: https://github.com/launchbadge/sqlx/pull/1652\n[#1657]: https://github.com/launchbadge/sqlx/pull/1657\n[#1658]: https://github.com/launchbadge/sqlx/pull/1658\n[#1661]: https://github.com/launchbadge/sqlx/pull/1661\n[#1665]: https://github.com/launchbadge/sqlx/pull/1665\n[#1667]: https://github.com/launchbadge/sqlx/pull/1667\n[#1680]: https://github.com/launchbadge/sqlx/pull/1680\n[#1684]: https://github.com/launchbadge/sqlx/pull/1684\n[#1685]: https://github.com/launchbadge/sqlx/pull/1685\n[#1687]: https://github.com/launchbadge/sqlx/pull/1687\n[#1692]: https://github.com/launchbadge/sqlx/pull/1692\n[#1696]: https://github.com/launchbadge/sqlx/pull/1696\n[#1710]: https://github.com/launchbadge/sqlx/pull/1710\n\n[0.5.11-prs]: https://github.com/launchbadge/sqlx/pulls?q=is%3Apr+is%3Amerged+merged%3A2021-12-30..2022-02-17\n\n## 0.5.10 - 2021-12-29\n[A whopping 31 pull requests][0.5.10-prs] were merged this release cycle!\n\nAccording to this changelog, we saw 18 new contributors! However, some of these folks may have missed getting\nmentioned in previous entries since we only listed highlights. To avoid anyone feeling left out, I put in the effort\nthis time and tried to list every single one here.\n\n### Added\n* [[#1228]]: Add `Pool::any_kind()` [[@nitnelave]]\n* [[#1343]]: Add `Encode/Decode` impl for `Cow<'_, str>` [[@Drevoed]]\n* [[#1474]]: Derive `Clone`, `Copy` for `AnyKind` [[@yuyawk]]\n* [[#1497]]: Update FAQ to explain how to configure docs.rs to build a project using SQLx [[@russweas]]\n* [[#1498]]: Add description of migration file structure to `migrate!()` docs [[@zbigniewzolnierowicz]]\n* [[#1508]]: Add `.persistent(bool)` to `QueryAs`, `QueryScalar` [[@akiradeveloper]]\n* [[#1514]]: Add support for serialized threading mode to SQLite [[@LLBlumire]]\n* [[#1523]]: Allow `rust_decimal::Decimal` in `PgRange` [[@meh]]\n* [[#1539]]: Support `PGOPTIONS` and adding custom configuration options in `PgConnectOptions` [[@liushuyu]]\n* [[#1562]]: Re-export `either::Either` used by `Executor::fetch_many()` [[@DoumanAsh]]\n* [[#1584]]: Add feature to use RusTLS instead of `native-tls` for `sqlx-cli` [[@SonicZentropy]]\n* [[#1592]]: Add `AnyConnection::kind()` [[@05storm26]]\n\n### Changes\n* [[#1385]]: Rewrite Postgres array handling to reduce boilerplate and allow custom types [[@jplatte]]\n* [[#1479]]: Remove outdated mention of `runtime-async-std-native-tls` as the default runtime in README.md [[@yerke]]\n* [[#1526]]: Revise `Pool` docs in a couple places [[@abonander]]\n* [[#1535]]: Bump `libsqlite-sys` to `0.23.1` [[@nitsky]]\n* [[#1551]]: SQLite: make worker thread responsible for all FFI calls [[@abonander]]\n    * If you were encountering segfaults with the SQLite driver, there's a good chance this will fix it!\n* [[#1557]]: CI: test with Postgres 14 [[@paolobarbolini]]\n* [[#1571]]: Make `whoami` dep optional, only pull it in for Postgres [[@joshtriplett]]\n* [[#1572]]: Update `rsa` crate to 0.5 [[@paolobarbolini]]\n* [[#1591]]: List SeaORM as an ORM option in the README [[@kunjee17]]\n* [[#1601]]: Update `itoa` and `dirs` [[@paolobarbolini]]\n\n### Fixes\n* [[#1475]]: Fix panic when converting a negative `chrono::Duration` to `PgInterval` [[@yuyawk]]\n* [[#1483]]: Fix error when decoding array of custom types from Postgres [[@demurgos]\n* [[#1501]]: Reduce `indexmap` version requirement to `1.6.2` [[@dimfeld]]\n* [[#1511]]: Fix element type given to Postgres for arrays of custom enums [[@chesedo]]\n* [[#1517]]: Fix mismatched type errors in MySQL type tests [[@abonander]]\n* [[#1537]]: Fix missing re-export of `PgCopyIn` [[@akiradeveloper]]\n* [[#1566]]: Match `~/.pgpass` password after URL parsing and fix user and database ordering [[@D1plo1d]]\n* [[#1582]]: `cargo sqlx prepare`: Append to existing `RUSTFLAGS` instead of overwriting [[@tkintscher]]\n* [[#1587]]: SQLite: if set, send `PRAGMA key` on a new connection before anything else. [[@parazyd]]\n    * This should fix problems with being unable to open databases using SQLCipher.\n    \n\n[#1228]: https://github.com/launchbadge/sqlx/pull/1228\n[#1343]: https://github.com/launchbadge/sqlx/pull/1343\n[#1385]: https://github.com/launchbadge/sqlx/pull/1385\n[#1474]: https://github.com/launchbadge/sqlx/pull/1474\n[#1475]: https://github.com/launchbadge/sqlx/pull/1475\n[#1479]: https://github.com/launchbadge/sqlx/pull/1479\n[#1483]: https://github.com/launchbadge/sqlx/pull/1483\n[#1497]: https://github.com/launchbadge/sqlx/pull/1497\n[#1498]: https://github.com/launchbadge/sqlx/pull/1498\n[#1501]: https://github.com/launchbadge/sqlx/pull/1501\n[#1508]: https://github.com/launchbadge/sqlx/pull/1508 \n[#1511]: https://github.com/launchbadge/sqlx/pull/1511\n[#1514]: https://github.com/launchbadge/sqlx/pull/1514\n[#1517]: https://github.com/launchbadge/sqlx/pull/1517\n[#1523]: https://github.com/launchbadge/sqlx/pull/1523\n[#1526]: https://github.com/launchbadge/sqlx/pull/1526\n[#1535]: https://github.com/launchbadge/sqlx/pull/1535\n[#1537]: https://github.com/launchbadge/sqlx/pull/1537\n[#1539]: https://github.com/launchbadge/sqlx/pull/1539\n[#1551]: https://github.com/launchbadge/sqlx/pull/1551\n[#1557]: https://github.com/launchbadge/sqlx/pull/1557\n[#1562]: https://github.com/launchbadge/sqlx/pull/1562\n[#1566]: https://github.com/launchbadge/sqlx/pull/1566\n[#1571]: https://github.com/launchbadge/sqlx/pull/1571\n[#1572]: https://github.com/launchbadge/sqlx/pull/1572\n[#1582]: https://github.com/launchbadge/sqlx/pull/1582\n[#1584]: https://github.com/launchbadge/sqlx/pull/1584\n[#1587]: https://github.com/launchbadge/sqlx/pull/1587\n[#1591]: https://github.com/launchbadge/sqlx/pull/1591\n[#1592]: https://github.com/launchbadge/sqlx/pull/1592\n[#1601]: https://github.com/launchbadge/sqlx/pull/1601\n[0.5.10-prs]: https://github.com/launchbadge/sqlx/pulls?page=1&q=is%3Apr+merged%3A2021-10-02..2021-12-31+sort%3Acreated-asc\n\n## 0.5.9 - 2021-10-01\n\nA hotfix release to address the issue of the `sqlx` crate itself still depending on older versions of `sqlx-core` and \n`sqlx-macros`.\n\nNo other changes from `0.5.8`.\n\n## 0.5.8 - 2021-10-01 (Yanked; use 0.5.9)\n\n[A total of 24 pull requests][0.5.8-prs] were merged this release cycle! Some highlights: \n\n* [[#1289]] Support the `immutable` option on SQLite connections [[@djmarcin]]\n* [[#1295]] Support custom initial options for SQLite [[@ghassmo]]\n    * Allows specifying custom `PRAGMA`s and overriding those set by SQLx.\n* [[#1345]] Initial support for Postgres `COPY FROM/TO`[[@montanalow], [@abonander]]\n* [[#1439]] Handle multiple waiting results correctly in MySQL [[@eagletmt]]\n\n[#1289]: https://github.com/launchbadge/sqlx/pull/1289\n[#1295]: https://github.com/launchbadge/sqlx/pull/1295\n[#1345]: https://github.com/launchbadge/sqlx/pull/1345\n[#1439]: https://github.com/launchbadge/sqlx/pull/1439\n[0.5.8-prs]: https://github.com/launchbadge/sqlx/pulls?q=is%3Apr+is%3Amerged+merged%3A2021-08-21..2021-10-01\n\n## 0.5.7 - 2021-08-20\n\n* [[#1392]] use `resolve_path` when getting path for `include_str!()` [[@abonander]]\n    * Fixes a regression introduced by [[#1332]].\n* [[#1393]] avoid recursively spawning tasks in `PgListener::drop()` [[@abonander]]\n    * Fixes a panic that occurs when `PgListener` is dropped in `async fn main()`.\n\n[#1392]: https://github.com/launchbadge/sqlx/pull/1392\n[#1393]: https://github.com/launchbadge/sqlx/pull/1393\n\n## 0.5.6 - 2021-08-16\n\nA large bugfix release, including but not limited to:\n\n* [[#1329]] Implement `MACADDR` type for Postgres [[@nomick]]\n* [[#1363]] Fix `PortalSuspended` for array of composite types in Postgres [[@AtkinsChang]]\n* [[#1320]] Reimplement `sqlx::Pool` internals using `futures-intrusive` [[@abonander]]\n    * This addresses a number of deadlocks/stalls on acquiring connections from the pool.\n* [[#1332]] Macros: tell the compiler about external files/env vars to watch [[@abonander]]\n    * Includes `sqlx build-script` to create a `build.rs` to watch `migrations/` for changes.\n    * Nightly users can try `RUSTFLAGS=--cfg sqlx_macros_unstable` to tell the compiler \n      to watch `migrations/` for changes instead of using a build script. \n    * See the new section in the docs for `sqlx::migrate!()` for details.\n* [[#1351]] Fix a few sources of segfaults/errors in SQLite driver [[@abonander]]\n    * Includes contributions from [[@link2ext]] and [[@madadam]].\n* [[#1323]] Keep track of column typing in SQLite EXPLAIN parsing [[@marshoepial]]\n    * This fixes errors in the macros when using `INSERT/UPDATE/DELETE ... RETURNING ...` in SQLite.\n    \n[A total of 25 pull requests][0.5.6-prs] were merged this release cycle!\n\n[#1329]: https://github.com/launchbadge/sqlx/pull/1329\n[#1363]: https://github.com/launchbadge/sqlx/pull/1363\n[#1320]: https://github.com/launchbadge/sqlx/pull/1320\n[#1332]: https://github.com/launchbadge/sqlx/pull/1332\n[#1351]: https://github.com/launchbadge/sqlx/pull/1351\n[#1323]: https://github.com/launchbadge/sqlx/pull/1323\n[0.5.6-prs]: https://github.com/launchbadge/sqlx/pulls?q=is%3Apr+is%3Amerged+merged%3A2021-05-24..2021-08-17\n\n## 0.5.5 - 2021-05-24\n\n-   [[#1242]] Fix infinite loop at compile time when using query macros [[@toshokan]]\n\n[#1242]: https://github.com/launchbadge/sqlx/pull/1242\n\n## 0.5.4 - 2021-05-22\n\n-   [[#1235]] Fix compilation with rustls from an eager update to webpki [[@ETCaton]]\n\n[#1235]: https://github.com/launchbadge/sqlx/pull/1235\n\n## 0.5.3 - 2021-05-21\n\n-   [[#1211]] Even more tweaks and fixes to the Pool internals [[@abonander]]\n\n-   [[#1213]] Add support for bytes and `chrono::NaiveDateTime` to `Any` [[@guylapid]]\n\n-   [[#1224]] Add support for `chrono::DateTime<Local>` to `Any` with `MySQL` [[@NatPRoach]]\n\n-   [[#1216]] Skip empty lines and comments in pgpass files [[@feikesteenbergen]]\n\n-   [[#1218]] Add support for `PgMoney` to the compile-time type-checking [[@iamsiddhant05]]\n\n[#1211]: https://github.com/launchbadge/sqlx/pull/1211\n[#1213]: https://github.com/launchbadge/sqlx/pull/1213\n[#1216]: https://github.com/launchbadge/sqlx/pull/1216\n[#1218]: https://github.com/launchbadge/sqlx/pull/1218\n[#1224]: https://github.com/launchbadge/sqlx/pull/1224\n\n## 0.5.2 - 2021-04-15\n\n-   [[#1149]] Tweak and optimize Pool internals [[@abonander]]\n\n-   [[#1132]] Remove `'static` bound on `Connection::transaction` [[@argv-minus-one]]\n\n-   [[#1128]] Fix `-y` flag for `sqlx db reset -y` [[@qqwa]]\n\n-   [[#1099]] [[#1097]] Truncate buffer when `BufStream` is dropped [[@Diggsey]]\n\n[#1132]: https://github.com/launchbadge/sqlx/pull/1132\n[#1149]: https://github.com/launchbadge/sqlx/pull/1149\n[#1128]: https://github.com/launchbadge/sqlx/pull/1128\n[#1099]: https://github.com/launchbadge/sqlx/pull/1099\n[#1097]: https://github.com/launchbadge/sqlx/issues/1097\n\n### PostgreSQL\n\n-   [[#1170]] Remove `Self: Type` bounds in `Encode` / `Decode` implementations for arrays [[@jplatte]]\n\n    Enables working around the lack of support for user-defined array types:\n\n    ```rust\n    #[derive(sqlx::Encode)]\n    struct Foos<'a>(&'a [Foo]);\n\n    impl sqlx::Type<sqlx::Postgres> for Foos<'_> {\n        fn type_info() -> PgTypeInfo {\n            PgTypeInfo::with_name(\"_foo\")\n        }\n    }\n\n    query_as!(\n        Whatever,\n        \"<QUERY with $1 of type foo[]>\",\n        Foos(&foo_vec) as _,\n    )\n    ```\n\n-   [[#1141]] Use `u16::MAX` instead of `i16::MAX` for a check against the largest number of parameters in a query [[@crajcan]]\n\n-   [[#1112]] Add support for `DOMAIN` types [[@demurgos]]\n\n-   [[#1100]] Explicitly `UNLISTEN` before returning connections to the pool in `PgListener` [[@Diggsey]]\n\n[#1170]: https://github.com/launchbadge/sqlx/pull/1170\n[#1141]: https://github.com/launchbadge/sqlx/pull/1141\n[#1112]: https://github.com/launchbadge/sqlx/pull/1112\n[#1100]: https://github.com/launchbadge/sqlx/pull/1100\n\n### SQLite\n\n-   [[#1161]] Catch `SQLITE_MISUSE` on connection close and panic [[@link2xt]]\n\n-   [[#1160]] Do not cast pointers to `i32` (cast to `usize`) [[@link2xt]]\n\n-   [[#1156]] Reset the statement when `fetch_many` stream is dropped [[@link2xt]]\n\n[#1161]: https://github.com/launchbadge/sqlx/pull/1161\n[#1160]: https://github.com/launchbadge/sqlx/pull/1160\n[#1156]: https://github.com/launchbadge/sqlx/pull/1156\n\n## 0.5.1 - 2021-02-04\n\n-   Update sqlx-rt to 0.3.\n\n## 0.5.0 - 2021-02-04\n\n### Changes\n\n-   [[#983]] [[#1022]] Upgrade async runtime dependencies [[@seryl], [@ant32], [@jplatte], [@robjtede]]\n\n    -   tokio 1.0\n    -   actix-rt 2.0\n\n-   [[#854]] Allow chaining `map` and `try_map` [[@jplatte]]\n\n    Additionally enables calling these combinators with the macros:\n\n    ```rust\n    let ones: Vec<i32> = query!(\"SELECT 1 as foo\")\n        .map(|row| row.foo)\n        .fetch_all(&mut conn).await?;\n    ```\n\n-   [[#940]] Rename the `#[sqlx(rename)]` attribute used to specify the type name on the database\n    side to `#[sqlx(type_name)]` [[@jplatte]].\n\n-   [[#976]] Rename the `DbDone` types to `DbQueryResult`. [[@jplatte]]\n\n-   [[#976]] Remove the `Done` trait. The `.rows_affected()` method is now available as an inherent\n    method on `PgQueryResult`, `MySqlQueryResult` and so on. [[@jplatte]]\n\n-   [[#1007]] Remove `any::AnyType` (and replace with directly implementing `Type<Any>`) [[@jplatte]]\n\n### Added\n\n-   [[#998]] [[#821]] Add `.constraint()` to `DatabaseError` [[@fl9]]\n\n-   [[#919]] For SQLite, add support for unsigned integers [[@dignifiedquire]]\n\n### Fixes\n\n-   [[#1002]] For SQLite, `GROUP BY` in `query!` caused an infinite loop at compile time. [[@pymongo]]\n\n-   [[#979]] For MySQL, fix support for non-default authentication. [[@sile]]\n\n-   [[#918]] Recover from dropping `wait_for_conn` inside Pool. [[@antialize]]\n\n[#821]: https://github.com/launchbadge/sqlx/issues/821\n[#918]: https://github.com/launchbadge/sqlx/pull/918\n[#919]: https://github.com/launchbadge/sqlx/pull/919\n[#983]: https://github.com/launchbadge/sqlx/pull/983\n[#940]: https://github.com/launchbadge/sqlx/pull/940\n[#976]: https://github.com/launchbadge/sqlx/pull/976\n[#979]: https://github.com/launchbadge/sqlx/pull/979\n[#998]: https://github.com/launchbadge/sqlx/pull/998\n[#983]: https://github.com/launchbadge/sqlx/pull/983\n[#1002]: https://github.com/launchbadge/sqlx/pull/1002\n[#1007]: https://github.com/launchbadge/sqlx/pull/1007\n[#1022]: https://github.com/launchbadge/sqlx/pull/1022\n\n## 0.4.2 - 2020-12-19\n\n-   [[#908]] Fix `whoami` crash on FreeBSD platform [[@fundon]] [[@AldaronLau]]\n\n-   [[#895]] Decrement pool size when connection is released [[@andrewwhitehead]]\n\n-   [[#878]] Fix `conn.transaction` wrapper [[@hamza1311]]\n\n    ```rust\n    conn.transaction(|transaction: &mut Transaction<Database> | {\n        // ...\n    });\n    ```\n\n-   [[#874]] Recognize `1` as `true` for `SQLX_OFFLINE [[@Pleto]]\n\n-   [[#747]] [[#867]] Replace `lru-cache` with `hashlink` [[@chertov]]\n\n-   [[#860]] Add `rename_all` to `FromRow` and add `camelCase` and `PascalCase` [[@framp]]\n\n-   [[#839]] Add (optional) support for `bstr::BStr`, `bstr::BString`, and `git2::Oid` [[@joshtriplett]]\n\n#### SQLite\n\n-   [[#893]] Fix memory leak if `create_collation` fails [[@slumber]]\n\n-   [[#852]] Fix potential 100% CPU usage in `fetch_one` / `fetch_optional` [[@markazmierczak]]\n\n-   [[#850]] Add `synchronous` option to `SqliteConnectOptions` [[@markazmierczak]]\n\n#### PostgreSQL\n\n-   [[#889]] Fix decimals (one more time) [[@slumber]]\n\n-   [[#876]] Add support for `BYTEA[]` to compile-time type-checking [[@augustocdias]]\n\n-   [[#845]] Fix path for `&[NaiveTime]` in `query!` macros [[@msrd0]]\n\n#### MySQL\n\n-   [[#880]] Consider `utf8mb4_general_ci` as a string [[@mcronce]]\n\n[#908]: https://github.com/launchbadge/sqlx/pull/908\n[#895]: https://github.com/launchbadge/sqlx/pull/895\n[#893]: https://github.com/launchbadge/sqlx/pull/893\n[#889]: https://github.com/launchbadge/sqlx/pull/889\n[#880]: https://github.com/launchbadge/sqlx/pull/880\n[#878]: https://github.com/launchbadge/sqlx/pull/878\n[#876]: https://github.com/launchbadge/sqlx/pull/876\n[#874]: https://github.com/launchbadge/sqlx/pull/874\n[#867]: https://github.com/launchbadge/sqlx/pull/867\n[#860]: https://github.com/launchbadge/sqlx/pull/860\n[#854]: https://github.com/launchbadge/sqlx/pull/854\n[#852]: https://github.com/launchbadge/sqlx/pull/852\n[#850]: https://github.com/launchbadge/sqlx/pull/850\n[#845]: https://github.com/launchbadge/sqlx/pull/845\n[#839]: https://github.com/launchbadge/sqlx/pull/839\n[#747]: https://github.com/launchbadge/sqlx/issues/747\n\n## 0.4.1 – 2020-11-13\n\nFix docs.rs build by enabling a runtime feature in the docs.rs metadata in `Cargo.toml`.\n\n## 0.4.0 - 2020-11-12\n\n-   [[#774]] Fix usage of SQLx derives with other derive crates [[@NyxCode]]\n\n-   [[#762]] Fix `migrate!()` (with no params) [[@esemeniuc]]\n\n-   [[#755]] Add `kebab-case` to `rename_all` [[@iamsiddhant05]]\n\n-   [[#735]] Support `rustls` [[@jplatte]]\n\n    Adds `-native-tls` or `-rustls` on each runtime feature:\n\n    ```toml\n    # previous\n    features = [ \"runtime-async-std\" ]\n\n    # now\n    features = [ \"runtime-async-std-native-tls\" ]\n    ```\n\n-   [[#718]] Support tuple structs with `#[derive(FromRow)]` [[@dvermd]]\n\n#### SQLite\n\n-   [[#789]] Support `$NNN` parameters [[@nitsky]]\n\n-   [[#784]] Use `futures_channel::oneshot` in worker for big perf win [[@markazmierczak]]\n\n#### PostgreSQL\n\n-   [[#781]] Fix decimal conversions handling of `0.01` [[@pimeys]]\n\n-   [[#745]] Always prefer parsing of the non-localized notice severity field [[@dstoeckel]]\n\n-   [[#742]] Enable `Vec<DateTime<Utc>>` with chrono [[@mrcd]]\n\n#### MySQL\n\n-   [[#743]] Consider `utf8mb4_bin` as a string [[@digorithm]]\n\n-   [[#739]] Fix minor protocol detail with `iteration-count` that was blocking Vitess [[@mcronce]]\n\n[#774]: https://github.com/launchbadge/sqlx/pull/774\n[#789]: https://github.com/launchbadge/sqlx/pull/789\n[#784]: https://github.com/launchbadge/sqlx/pull/784\n[#781]: https://github.com/launchbadge/sqlx/pull/781\n[#762]: https://github.com/launchbadge/sqlx/pull/762\n[#755]: https://github.com/launchbadge/sqlx/pull/755\n[#745]: https://github.com/launchbadge/sqlx/pull/745\n[#743]: https://github.com/launchbadge/sqlx/pull/743\n[#742]: https://github.com/launchbadge/sqlx/pull/742\n[#735]: https://github.com/launchbadge/sqlx/pull/735\n[#739]: https://github.com/launchbadge/sqlx/pull/739\n[#718]: https://github.com/launchbadge/sqlx/pull/718\n\n## 0.4.0-beta.1 - 2020-07-27\n\n### Highlights\n\n-   Enable compile-time type checking from cached metadata to enable building\n    in an environment without access to a development database (e.g., Docker, CI).\n\n-   Initial support for **Microsoft SQL Server**. If there is something missing that you need,\n    open an issue. We are happy to help.\n\n-   SQL migrations, both with a CLI tool and programmatically loading migrations at runtime.\n\n-   Runtime-determined database driver, `Any`, to support compile-once and run with a database\n    driver selected at runtime.\n\n-   Support for user-defined types and more generally overriding the inferred Rust type from SQL\n    with compile-time SQL verification.\n\n### Fixed\n\n#### MySQL\n\n-   [[#418]] Support zero dates and times [[@blackwolf12333]]\n\n### Added\n\n-   [[#174]] Inroduce a builder to construct connections to bypass the URL parsing\n\n    ```rust\n    // MSSQL\n    let conn = MssqlConnectOptions::new()\n        .host(\"localhost\")\n        .database(\"master\")\n        .username(\"sa\")\n        .password(\"Password\")\n        .connect().await?;\n\n    // SQLite\n    let conn = SqliteConnectOptions::from_str(\"sqlite://a.db\")?\n        .foreign_keys(false)\n        .connect().await?;\n    ```\n\n-   [[#127]] Get the last ID or Row ID inserted for MySQL or SQLite\n\n    ```rust\n    // MySQL\n    let id: u64 = query!(\"INSERT INTO table ( col ) VALUES ( ? )\", val)\n        .execute(&mut conn).await?\n        .last_insert_id(); // LAST_INSERT_ID()\n\n    // SQLite\n    let id: i64 = query!(\"INSERT INTO table ( col ) VALUES ( ?1 )\", val)\n        .execute(&mut conn).await?\n        .last_insert_rowid(); // sqlite3_last_insert_rowid()\n    ```\n\n-   [[#263]] Add hooks to the Pool: `after_connect`, `before_release`, and `after_acquire`\n\n    ```rust\n    // PostgreSQL\n    let pool = PgPoolOptions::new()\n        .after_connect(|conn| Box::pin(async move {\n            conn.execute(\"SET application_name = 'your_app';\").await?;\n            conn.execute(\"SET search_path = 'my_schema';\").await?;\n\n            Ok(())\n        }))\n        .connect(\"postgres:// …\").await?\n    ```\n\n-   [[#308]] [[#495]] Extend `derive(FromRow)` with support for `#[sqlx(default)]` on fields to allow reading in a partial query [[@OriolMunoz]]\n\n-   [[#454]] [[#456]] Support `rust_decimal::Decimal` as an alternative to `bigdecimal::BigDecimal` for `NUMERIC` columns in MySQL and PostgreSQL [[@pimeys]]\n\n-   [[#181]] Column names and type information is now accessible from `Row` via `Row::columns()` or `Row::column(name)`\n\n#### PostgreSQL\n\n-   [[#197]] [[#271]] Add initial support for `INTERVAL` (full support pending a `time::Period` type) [[@dimtion]]\n\n#### MySQL\n\n-   [[#449]] [[#450]] Support Unix Domain Sockets (UDS) for MySQL [[@pimeys]]\n\n#### SQLite\n\n-   Types are now inferred for expressions. This means its now possible to use `query!` and `query_as!` for:\n\n    ```rust\n    let row = query!(\"SELECT 10 as _1, x + 5 as _2 FROM table\").fetch_one(&mut conn).await?;\n\n    assert_eq!(row._1, 10);\n    assert_eq!(row._2, 5); // 5 + x?\n    ```\n\n-   [[#167]] Support `foreign_keys` explicitly with a `foreign_keys(true)` method available on `SqliteConnectOptions` which is a builder\n    for new SQLite connections (and can be passed into `PoolOptions` to build a pool).\n\n    ```rust\n    let conn = SqliteConnectOptions::new()\n        .foreign_keys(true) // on by default\n        .connect().await?;\n    ```\n\n-   [[#430]] [[#438]] Add method to get the raw SQLite connection handle [[@agentsim]]\n\n    ```rust\n    // conn is `SqliteConnection`\n    // this is not unsafe, but what you do with the handle will be\n    let ptr: *mut libsqlite3::sqlite3 = conn.as_raw_handle();\n    ```\n\n-   [[#164]] Support `TIMESTAMP`, `DATETIME`, `DATE`, and `TIME` via `chrono` in SQLite [[@felipesere]] [[@meteficha]]\n\n### Changed\n\n-   `Transaction` now mutably borrows a connection instead of owning it. This enables a new (or nested) transaction to be started from `&mut conn`.\n\n-   [[#145]] [[#444]] Use a least-recently-used (LRU) cache to limit the growth of the prepared statement cache for SQLite, MySQL, and PostgreSQL [[@pimeys]]\n\n#### SQLite\n\n-   [[#499]] `INTEGER` now resolves to `i64` instead of `i32`, `INT4` will still resolve to `i32`\n\n### Removed\n\n[#127]: https://github.com/launchbadge/sqlx/issues/127\n[#174]: https://github.com/launchbadge/sqlx/issues/174\n[#145]: https://github.com/launchbadge/sqlx/issues/145\n[#164]: https://github.com/launchbadge/sqlx/issues/164\n[#167]: https://github.com/launchbadge/sqlx/issues/167\n[#181]: https://github.com/launchbadge/sqlx/issues/181\n[#197]: https://github.com/launchbadge/sqlx/issues/197\n[#263]: https://github.com/launchbadge/sqlx/issues/263\n[#308]: https://github.com/launchbadge/sqlx/issues/308\n[#418]: https://github.com/launchbadge/sqlx/issues/418\n[#430]: https://github.com/launchbadge/sqlx/issues/430\n[#449]: https://github.com/launchbadge/sqlx/issues/449\n[#499]: https://github.com/launchbadge/sqlx/issues/499\n[#454]: https://github.com/launchbadge/sqlx/issues/454\n[#271]: https://github.com/launchbadge/sqlx/pull/271\n[#444]: https://github.com/launchbadge/sqlx/pull/444\n[#438]: https://github.com/launchbadge/sqlx/pull/438\n[#495]: https://github.com/launchbadge/sqlx/pull/495\n[#495]: https://github.com/launchbadge/sqlx/pull/495\n\n## 0.3.5 - 2020-05-06\n\n### Fixed\n\n-   [[#259]] Handle percent-encoded paths for SQLite [[@g-s-k]]\n\n-   [[#281]] Deallocate SQLite statements before closing the SQLite connection [[@hasali19]]\n\n-   [[#284]] Fix handling of `0` for `BigDecimal` in PostgreSQL and MySQL [[@abonander]]\n\n### Added\n\n-   [[#256]] Add `query_unchecked!` and `query_file_unchecked!` with similar semantics to `query_as_unchecked!` [[@meh]]\n\n-   [[#252]] [[#297]] Derive several traits for the `Json<T>` wrapper type [[@meh]]\n\n-   [[#261]] Add support for `#[sqlx(rename_all = \"snake_case\")]` to `#[derive(Type)]` [[@shssoichiro]]\n\n-   [[#253]] Add support for UNIX domain sockets to PostgreSQL [[@Nilix007]]\n\n-   [[#251]] Add support for textual JSON on MySQL [[@blackwolf12333]]\n\n-   [[#275]] [[#268]] Optionally log formatted SQL queries on execution [[@shssoichiro]]\n\n-   [[#267]] Support Cargo.toml relative `.env` files; allows for each crate in a workspace to use their own `.env` file and thus their own `DATABASE_URL` [[@xyzd]]\n\n[#252]: https://github.com/launchbadge/sqlx/pull/252\n[#261]: https://github.com/launchbadge/sqlx/pull/261\n[#256]: https://github.com/launchbadge/sqlx/pull/256\n[#259]: https://github.com/launchbadge/sqlx/pull/259\n[#253]: https://github.com/launchbadge/sqlx/pull/253\n[#297]: https://github.com/launchbadge/sqlx/pull/297\n[#251]: https://github.com/launchbadge/sqlx/pull/251\n[#275]: https://github.com/launchbadge/sqlx/pull/275\n[#267]: https://github.com/launchbadge/sqlx/pull/267\n[#268]: https://github.com/launchbadge/sqlx/pull/268\n[#281]: https://github.com/launchbadge/sqlx/pull/281\n[#284]: https://github.com/launchbadge/sqlx/pull/284\n\n## 0.3.4 - 2020-04-10\n\n### Fixed\n\n-   [[#241]] Type name for custom enum is not always attached to TypeInfo in PostgreSQL\n\n-   [[#237]] [[#238]] User-defined type name matching is now case-insensitive in PostgreSQL [[@qtbeee]]\n\n-   [[#231]] Handle empty queries (and those with comments) in SQLite\n\n-   [[#228]] Provide `MapRow` implementations for functions (enables `.map(|row| ...)` over `.try_map(|row| ...)`)\n\n### Added\n\n-   [[#234]] Add support for `NUMERIC` in MySQL with the `bigdecimal` crate [[@xiaopengli89]]\n\n-   [[#227]] Support `#[sqlx(rename = \"new_name\")]` on struct fields within a `FromRow` derive [[@sidred]]\n\n[#228]: https://github.com/launchbadge/sqlx/issues/228\n[#231]: https://github.com/launchbadge/sqlx/issues/231\n[#237]: https://github.com/launchbadge/sqlx/issues/237\n[#241]: https://github.com/launchbadge/sqlx/issues/241\n[#227]: https://github.com/launchbadge/sqlx/pull/227\n[#234]: https://github.com/launchbadge/sqlx/pull/234\n[#238]: https://github.com/launchbadge/sqlx/pull/238\n\n## 0.3.3 - 2020-04-01\n\n### Fixed\n\n-   [[#214]] Handle percent-encoded usernames in a database URL [[@jamwaffles]]\n\n### Changed\n\n-   [[#216]] Mark `Cursor`, `Query`, `QueryAs`, `query::Map`, and `Transaction` as `#[must_use]` [[@Ace4896]]\n\n-   [[#213]] Remove matches dependency and use matches macro from std [[@nrjais]]\n\n[#216]: https://github.com/launchbadge/sqlx/pull/216\n[#214]: https://github.com/launchbadge/sqlx/pull/214\n[#213]: https://github.com/launchbadge/sqlx/pull/213\n\n## 0.3.2 - 2020-03-31\n\n### Fixed\n\n-   [[#212]] Removed sneaky `println!` in `MySqlCursor`\n\n[#212]: https://github.com/launchbadge/sqlx/issues/212\n\n## 0.3.1 - 2020-03-30\n\n### Fixed\n\n-   [[#203]] Allow an empty password for MySQL\n\n-   [[#204]] Regression in error reporting for invalid SQL statements on PostgreSQL\n\n-   [[#200]] Fixes the incorrect handling of raw (`r#...`) fields of a struct in the `FromRow` derive [[@sidred]]\n\n[#200]: https://github.com/launchbadge/sqlx/pull/200\n[#203]: https://github.com/launchbadge/sqlx/issues/203\n[#204]: https://github.com/launchbadge/sqlx/issues/204\n\n## 0.3.0 - 2020-03-29\n\n### Breaking Changes\n\n-   `sqlx::Row` now has a lifetime (`'c`) tied to the database connection. In effect, this means that you cannot store `Row`s or collect\n    them into a collection. `Query` (returned from `sqlx::query()`) has `map()` which takes a function to map from the `Row` to\n    another type to make this transition easier.\n\n    In 0.2.x\n\n    ```rust\n    let rows = sqlx::query(\"SELECT 1\")\n        .fetch_all(&mut conn).await?;\n    ```\n\n    In 0.3.x\n\n    ```rust\n    let values: Vec<i32> = sqlx::query(\"SELECT 1\")\n        .map(|row: PgRow| row.get(0))\n        .fetch_all(&mut conn).await?;\n    ```\n\n    To assist with the above, `sqlx::query_as()` now supports querying directly into tuples (up to 9 elements) or\n    struct types with a `#[derive(FromRow)]`.\n\n    ```rust\n    // This extension trait is needed until a rust bug is fixed\n    use sqlx::postgres::PgQueryAs;\n\n    let values: Vec<(i32, bool)> = sqlx::query_as(\"SELECT 1, false\")\n        .fetch_all(&mut conn).await?;\n    ```\n\n-   `HasSqlType<T>: Database` is now `T: Type<Database>` to mirror `Encode` and `Decode`\n\n-   `Query::fetch` (returned from `query()`) now returns a new `Cursor` type. `Cursor` is a Stream-like type where the\n    item type borrows into the stream (which itself borrows from connection). This means that using `query().fetch()` you can now\n    stream directly from the database with **zero-copy** and **zero-allocation**.\n\n-   Remove `PgTypeInfo::with_oid` and replace with `PgTypeInfo::with_name`\n\n### Added\n\n-   Results from the database are now zero-copy and no allocation beyond a shared read buffer\n    for the TCP stream ( in other words, almost no per-query allocation ). Bind arguments still\n    do allocate a buffer per query.\n\n-   [[#129]] Add support for [SQLite](https://sqlite.org/index.html). Generated code should be very close to normal use of the C API.\n\n    -   Adds `Sqlite`, `SqliteConnection`, `SqlitePool`, and other supporting types\n\n-   [[#97]] [[#134]] Add support for user-defined types. [[@Freax13]]\n\n    -   Rust-only domain types or transparent wrappers around SQL types. These may be used _transparently_ inplace of\n        the SQL type.\n\n        ```rust\n        #[derive(sqlx::Type)]\n        #[repr(transparent)]\n        struct Meters(i32);\n        ```\n\n    -   Enumerations may be defined in Rust and can match SQL by integer discriminant or variant name.\n\n        ```rust\n        #[derive(sqlx::Type)]\n        #[repr(i32)] // Expects a INT in SQL\n        enum Color { Red = 1, Green = 2, Blue = 3 }\n        ```\n\n        ```rust\n        #[derive(sqlx::Type)]\n        #[sqlx(rename = \"TEXT\")] // May also be the name of a user defined enum type\n        #[sqlx(rename_all = \"lowercase\")] // similar to serde rename_all\n        enum Color { Red, Green, Blue } // expects 'red', 'green', or 'blue'\n        ```\n\n    -   **Postgres** further supports user-defined composite types.\n\n        ```rust\n        #[derive(sqlx::Type)]\n        #[sqlx(rename = \"interface_type\")]\n        struct InterfaceType {\n            name: String,\n            supplier_id: i32,\n            price: f64\n        }\n        ```\n\n-   [[#98]] [[#131]] Add support for asynchronous notifications in Postgres (`LISTEN` / `NOTIFY`). [[@thedodd]]\n\n    -   Supports automatic reconnection on connection failure.\n\n    -   `PgListener` implements `Executor` and may be used to execute queries. Be careful however as if the\n        intent is to handle and process messages rapidly you don't want to be tying up the connection\n        for too long. Messages received during queries are buffered and will be delivered on the next call\n        to `recv()`.\n\n    ```rust\n    let mut listener = PgListener::new(DATABASE_URL).await?;\n\n    listener.listen(\"topic\").await?;\n\n    loop {\n        let message = listener.recv().await?;\n\n        println!(\"payload = {}\", message.payload);\n    }\n    ```\n\n-   Add _unchecked_ variants of the query macros. These will still verify the SQL for syntactic and\n    semantic correctness with the current database but they will not check the input or output types.\n\n    This is intended as a temporary solution until `query_as!` is able to support user defined types.\n\n    -   `query_as_unchecked!`\n    -   `query_file_as_unchecked!`\n\n-   Add support for many more types in Postgres\n\n    -   `JSON`, `JSONB` [[@oeb25]]\n    -   `INET`, `CIDR` [[@PoiScript]]\n    -   Arrays [[@oeb25]]\n    -   Composites ( Rust tuples or structs with a `#[derive(Type)]` )\n    -   `NUMERIC` [[@abonander]]\n    -   `OID` (`u32`)\n    -   `\"CHAR\"` (`i8`)\n    -   `TIMESTAMP`, `TIMESTAMPTZ`, etc. with the `time` crate [[@utter-step]]\n    -   Enumerations ( Rust enums with a `#[derive(Type)]` ) [[@Freax13]]\n\n### Changed\n\n-   `Query` (and `QueryAs`; returned from `query()`, `query_as()`, `query!()`, and `query_as!()`) now will accept both `&mut Connection` or\n    `&Pool` where as in 0.2.x they required `&mut &Pool`.\n\n-   `Executor` now takes any value that implements `Execute` as a query. `Execute` is implemented for `Query` and `QueryAs` to mean\n    exactly what they've meant so far, a prepared SQL query. However, `Execute` is also implemented for just `&str` which now performs\n    a raw or unprepared SQL query. You can further use this to fetch `Row`s from the database though it is not as efficient as the\n    prepared API (notably Postgres and MySQL send data back in TEXT mode as opposed to in BINARY mode).\n\n    ```rust\n    use sqlx::Executor;\n\n    // Set the time zone parameter\n    conn.execute(\"SET TIME ZONE LOCAL;\").await\n\n    // Demonstrate two queries at once with the raw API\n    let mut cursor = conn.fetch(\"SELECT 1; SELECT 2\");\n    let row = cursor.next().await?.unwrap();\n    let value: i32 = row.get(0); // 1\n    let row = cursor.next().await?.unwrap();\n    let value: i32 = row.get(0); // 2\n    ```\n\n### Removed\n\n-   `Query` (returned from `query()`) no longer has `fetch_one`, `fetch_optional`, or `fetch_all`. You _must_ map the row using `map()` and then\n    you will have a `query::Map` value that has the former methods available.\n\n    ```rust\n    let values: Vec<i32> = sqlx::query(\"SELECT 1\")\n        .map(|row: PgRow| row.get(0))\n        .fetch_all(&mut conn).await?;\n    ```\n\n### Fixed\n\n-   [[#62]] [[#130]] [[#135]] Remove explicit set of `IntervalStyle`. Allow usage of SQLx for CockroachDB and potentially PgBouncer. [[@bmisiak]]\n\n-   [[#108]] Allow nullable and borrowed values to be used as arguments in `query!` and `query_as!`. For example, where the column would\n    resolve to `String` in Rust (TEXT, VARCHAR, etc.), you may now use `Option<String>`, `Option<&str>`, or `&str` instead. [[@abonander]]\n\n-   [[#108]] Make unknown type errors far more informative. As an example, trying to `SELECT` a `DATE` column will now try and tell you about the\n    `chrono` feature. [[@abonander]]\n\n    ```\n    optional feature `chrono` required for type DATE of column #1 (\"now\")\n    ```\n\n[#62]: https://github.com/launchbadge/sqlx/issues/62\n[#130]: https://github.com/launchbadge/sqlx/issues/130\n[#98]: https://github.com/launchbadge/sqlx/pull/98\n[#97]: https://github.com/launchbadge/sqlx/pull/97\n[#134]: https://github.com/launchbadge/sqlx/pull/134\n[#129]: https://github.com/launchbadge/sqlx/pull/129\n[#131]: https://github.com/launchbadge/sqlx/pull/131\n[#135]: https://github.com/launchbadge/sqlx/pull/135\n[#108]: https://github.com/launchbadge/sqlx/pull/108\n\n## 0.2.6 - 2020-03-10\n\n### Added\n\n-   [[#114]] Export `sqlx_core::Transaction` [[@thedodd]]\n\n### Fixed\n\n-   [[#125]] [[#126]] Fix statement execution in MySQL if it contains NULL statement values [[@repnop]]\n\n-   [[#105]] [[#109]] Allow trailing commas in query macros [[@timmythetiny]]\n\n[#105]: https://github.com/launchbadge/sqlx/pull/105\n[#109]: https://github.com/launchbadge/sqlx/pull/109\n[#114]: https://github.com/launchbadge/sqlx/pull/114\n[#125]: https://github.com/launchbadge/sqlx/pull/125\n[#126]: https://github.com/launchbadge/sqlx/pull/126\n[@timmythetiny]: https://github.com/timmythetiny\n[@thedodd]: https://github.com/thedodd\n\n## 0.2.5 - 2020-02-01\n\n### Fixed\n\n-   Fix decoding of Rows containing NULLs in Postgres [#104]\n\n-   After a large review and some battle testing by [@ianthetechie](https://github.com/ianthetechie)\n    of the `Pool`, a live leaking issue was found. This has now been fixed by [@abonander] in [#84] which\n    included refactoring to make the pool internals less brittle (using RAII instead of manual\n    work is one example) and to help any future contributors when changing the pool internals.\n\n-   Passwords are now being percent-decoded before being presented to the server [[@repnop]]\n\n-   [@100] Fix `FLOAT` and `DOUBLE` decoding in MySQL\n\n[#84]: https://github.com/launchbadge/sqlx/issues/84\n[#100]: https://github.com/launchbadge/sqlx/issues/100\n[#104]: https://github.com/launchbadge/sqlx/issues/104\n\n### Added\n\n-   [[#72]] Add `PgTypeInfo::with_oid` to allow simple construction of `PgTypeInfo` which enables `HasSqlType`\n    to be implemented by downstream consumers of SQLx [[@jplatte]]\n\n-   [[#96]] Add support for returning columns from `query!` with a name of a rust keyword by\n    using raw identifiers [[@yaahc]]\n\n-   [[#71]] Implement derives for `Encode` and `Decode`. This is the first step to supporting custom types in SQLx. [[@Freax13]]\n\n[#72]: https://github.com/launchbadge/sqlx/issues/72\n[#96]: https://github.com/launchbadge/sqlx/issues/96\n[#71]: https://github.com/launchbadge/sqlx/issues/71\n\n## 0.2.4 - 2020-01-18\n\n### Fixed\n\n-   Fix decoding of Rows containing NULLs in MySQL (and add an integration test so this doesn't break again)\n\n## 0.2.3 - 2020-01-18\n\n### Fixed\n\n-   Fix `query!` when used on a query that does not return results\n\n## 0.2.2 - 2020-01-16\n\n### Added\n\n-   [[#57]] Add support for unsigned integers and binary types in `query!` for MySQL [[@mehcode]]\n\n[#57]: https://github.com/launchbadge/sqlx/issues/57\n\n### Fixed\n\n-   Fix stall when requesting TLS from a Postgres server that explicitly does not support TLS (such as postgres running inside docker) [[@abonander]]\n\n-   [[#66]] Declare used features for `tokio` in `sqlx-macros` explicitly\n\n[#66]: https://github.com/launchbadge/sqlx/issues/66\n\n## 0.2.1 - 2020-01-16\n\n### Fixed\n\n-   [[#64], [#65]] Fix decoding of Rows containing NULLs in MySQL [[@danielakhterov]]\n\n[#64]: https://github.com/launchbadge/sqlx/pull/64\n[#65]: https://github.com/launchbadge/sqlx/pull/65\n\n-   [[#55]] Use a shared tokio runtime for the `query!` macro compile-time execution (under the `runtime-tokio` feature) [[@udoprog]]\n\n[#55]: https://github.com/launchbadge/sqlx/pull/55\n\n## 0.2.0 - 2020-01-15\n\n### Fixed\n\n-   https://github.com/launchbadge/sqlx/issues/47\n\n### Added\n\n-   Support Tokio through an optional `runtime-tokio` feature.\n\n-   Support SQL transactions. You may now use the `begin()` function on `Pool` or `Connection` to\n    start a new SQL transaction. This returns `sqlx::Transaction` which will `ROLLBACK` on `Drop`\n    or can be explicitly `COMMIT` using `commit()`.\n\n-   Support TLS connections.\n\n## 0.1.4 - 2020-01-11\n\n### Fixed\n\n-   https://github.com/launchbadge/sqlx/issues/43\n\n-   https://github.com/launchbadge/sqlx/issues/40\n\n### Added\n\n-   Support for `SCRAM-SHA-256` authentication in Postgres [#37](https://github.com/launchbadge/sqlx/pull/37) [@danielakhterov](https://github.com/danielakhterov)\n\n-   Implement `Debug` for Pool [#42](https://github.com/launchbadge/sqlx/pull/42) [@prettynatty](https://github.com/prettynatty)\n\n## 0.1.3 - 2020-01-06\n\n### Fixed\n\n-   https://github.com/launchbadge/sqlx/issues/30\n\n## 0.1.2 - 2020-01-03\n\n### Added\n\n-   Support for Authentication in MySQL 5+ including the newer authentication schemes now default in MySQL 8: `mysql_native_password`, `sha256_password`, and `caching_sha2_password`.\n\n-   [`Chrono`](https://github.com/chronotope/chrono) support for MySQL was only partially implemented (was missing `NaiveTime` and `DateTime<Utc>`).\n\n-   `Vec<u8>` (and `[u8]`) support for MySQL (`BLOB`) and Postgres (`BYTEA`).\n\n[@abonander]: https://github.com/abonander\n[@danielakhterov]: https://github.com/danielakhterov\n[@mehcode]: https://github.com/mehcode\n[@udoprog]: https://github.com/udoprog\n[@jplatte]: https://github.com/jplatte\n[@yaahc]: https://github.com/yaahc\n[@freax13]: https://github.com/Freax13\n[@repnop]: https://github.com/repnop\n[@bmisiak]: https://github.com/bmisiak\n[@oeb25]: https://github.com/oeb25\n[@poiscript]: https://github.com/PoiScript\n[@utter-step]: https://github.com/utter-step\n[@sidred]: https://github.com/sidred\n[@ace4896]: https://github.com/Ace4896\n[@jamwaffles]: https://github.com/jamwaffles\n[@nrjais]: https://github.com/nrjais\n[@qtbeee]: https://github.com/qtbeee\n[@xiaopengli89]: https://github.com/xiaopengli89\n[@meh]: https://github.com/meh\n[@shssoichiro]: https://github.com/shssoichiro\n[@nilix007]: https://github.com/Nilix007\n[@g-s-k]: https://github.com/g-s-k\n[@blackwolf12333]: https://github.com/blackwolf12333\n[@xyzd]: https://github.com/xyzd\n[@hasali19]: https://github.com/hasali19\n[@oriolmunoz]: https://github.com/OriolMunoz\n[@pimeys]: https://github.com/pimeys\n[@agentsim]: https://github.com/agentsim\n[@meteficha]: https://github.com/meteficha\n[@felipesere]: https://github.com/felipesere\n[@dimtion]: https://github.com/dimtion\n[@fundon]: https://github.com/fundon\n[@aldaronlau]: https://github.com/AldaronLau\n[@andrewwhitehead]: https://github.com/andrewwhitehead\n[@slumber]: https://github.com/slumber\n[@mcronce]: https://github.com/mcronce\n[@hamza1311]: https://github.com/hamza1311\n[@augustocdias]: https://github.com/augustocdias\n[@pleto]: https://github.com/Pleto\n[@chertov]: https://github.com/chertov\n[@framp]: https://github.com/framp\n[@markazmierczak]: https://github.com/markazmierczak\n[@msrd0]: https://github.com/msrd0\n[@joshtriplett]: https://github.com/joshtriplett\n[@nyxcode]: https://github.com/NyxCode\n[@nitsky]: https://github.com/nitsky\n[@esemeniuc]: https://github.com/esemeniuc\n[@iamsiddhant05]: https://github.com/iamsiddhant05\n[@dstoeckel]: https://github.com/dstoeckel\n[@mrcd]: https://github.com/mrcd\n[@dvermd]: https://github.com/dvermd\n[@seryl]: https://github.com/seryl\n[@ant32]: https://github.com/ant32\n[@robjtede]: https://github.com/robjtede\n[@pymongo]: https://github.com/pymongo\n[@sile]: https://github.com/sile\n[@fl9]: https://github.com/fl9\n[@antialize]: https://github.com/antialize\n[@dignifiedquire]: https://github.com/dignifiedquire\n[@argv-minus-one]: https://github.com/argv-minus-one\n[@qqwa]: https://github.com/qqwa\n[@diggsey]: https://github.com/Diggsey\n[@crajcan]: https://github.com/crajcan\n[@demurgos]: https://github.com/demurgos\n[@link2xt]: https://github.com/link2xt\n[@guylapid]: https://github.com/guylapid\n[@natproach]: https://github.com/NatPRoach\n[@feikesteenbergen]: https://github.com/feikesteenbergen\n[@etcaton]: https://github.com/ETCaton\n[@toshokan]: https://github.com/toshokan\n[@nomick]: https://github.com/nomick\n[@marshoepial]: https://github.com/marshoepial\n[@link2ext]: https://github.com/link2ext\n[@madadam]: https://github.com/madadam\n[@AtkinsChang]: https://github.com/AtkinsChang\n[@djmarcin]: https://github.com/djmarcin\n[@ghassmo]: https://github.com/ghassmo\n[@eagletmt]: https://github.com/eagletmt\n[@montanalow]: https://github.com/montanalow\n[@nitnelave]: https://github.com/nitnelave\n[@Drevoed]: https://github.com/Drevoed\n[@yuyawk]: https://github.com/yuyawk\n[@yerke]: https://github.com/yerke\n[@russweas]: https://github.com/russweas\n[@zbigniewzolnierowicz]: https://github.com/zbigniewzolnierowicz\n[@dimfeld]: https://github.com/dimfeld\n[@akiradeveloper]: https://github.com/akiradeveloper\n[@chesedo]: https://github.com/chesedo\n[@LLBlumire]: https://github.com/LLBlumire\n[@liushuyu]: https://github.com/liushuyu\n[@paolobarbolini]: https://github.com/paolobarbolini\n[@DoumanAsh]: https://github.com/DoumanAsh\n[@D1plo1d]: https://github.com/D1plo1d\n[@tkintscher]: https://github.com/tkintscher\n[@SonicZentropy]: https://github.com/SonicZentropy\n[@parazyd]: https://github.com/parazyd\n[@kunjee17]: https://github.com/kunjee17\n[@05storm26]: https://github.com/05storm26\n[@dbeckwith]: https://github.com/dbeckwith\n[@k-jun]: https://github.com/k-jun\n[@tranzystorek-io]: https://github.com/tranzystorek-io\n[@taladar]: https://github.com/taladar\n[@genusistimelord]: https://github.com/genusistimelord\n[@p9s]: https://github.com/p9s\n[@ArGGu]: https://github.com/ArGGu\n[@sedrik]: https://github.com/sedrik\n[@nappa85]: https://github.com/nappa85\n[@ifn3]: https://github.com/ifn3\n[@LovecraftianHorror]: https://github.com/LovecraftianHorror\n[@stoically]: https://github.com/stoically\n[@VersBinarii]: https://github.com/VersBinarii\n[@cemoktra]: https://github.com/cemoktra\n[@jdrouet]: https://github.com/jdrouet\n[@vbmade2000]: https://github.com/vbmade2000\n[@abreis]: https://github.com/abreis\n[@0xdeafbeef]: https://github.com/0xdeafbeef\n[@Dylan-DPC]: https://github.com/Dylan-DPC\n[@carols10cents]: https://github.com/carols10cents\n[@david-mcgillicuddy-moixa]: https://github.com/david-mcgillicuddy-moixa\n[@ipetkov]: https://github.com/ipetkov\n[@pedromfedricci]: https://github.com/pedromfedricci\n[@tm-drtina]: https://github.com/tm-drtina\n[@espindola]: https://github.com/espindola\n[@mgrachev]: https://github.com/mgrachev\n[@tyrelr]: https://github.com/tyrelr\n[@SebastienGllmt]: https://github.com/SebastienGllmt\n[@e00E]: https://github.com/e00E\n[@sebpuetz]: https://github.com/sebpuetz\n[@pruthvikar]: https://github.com/pruthvikar\n[@tobymurray]: https://github.com/tobymurray\n[@djc]: https://github.com/djc\n[@mfreeborn]: https://github.com/mfreeborn\n[@scottwey]: https://github.com/scottwey\n[@e-rhodes]: https://github.com/e-rhodes\n[@OskarPersson]: https://github.com/OskarPersson\n[@walf443]: https://github.com/walf443\n[@lovasoa]: https://github.com/lovasoa\n[@mdtusz]: https://github.com/mdtusz\n[@kianmeng]: https://github.com/kianmeng\n[@EthanYuan]: https://github.com/EthanYuan\n[@Nukesor]: https://github.com/Nukesor\n[@smonv]: https://github.com/smonv\n[@Erik1000]: https://github.com/Erik1000\n[@raviqqe]: https://github.com/raviqqe\n[@johnbcodes]: https://github.com/johnbcodes\n[@sbeckeriv]: https://github.com/sbeckeriv\n[@RomainStorai]: https://github.com/RomainStorai\n[@jayy-lmao]: https://github.com/jayy-lmao\n[@Thomasdezeeuw]: https://github.com/Thomasdezeeuw\n[@kenkoooo]: https://github.com/kenkoooo\n[@TheoOiry]: https://github.com/TheoOiry\n[@JoeyMckenzie]: https://github.com/JoeyMckenzie\n[@ivan]: https://github.com/ivan\n[@crepererum]: https://github.com/crepererum\n[@UramnOIL]: https://github.com/UramnOIL\n[@liningpan]: https://github.com/liningpan\n[@zzhengzhuo]: https://github.com/zzhengzhuo\n[@crepererum]: https://github.com/crepererum\n[@szymek156]: https://github.com/szymek156\n[@NSMustache]: https://github.com/NSMustache\n[@RustyYato]: https://github.com/RustyYato\n[@alexander-jackson]: https://github.com/alexander-jackson\n[@zlidner]: https://github.com/zlidner\n[@zlindner]: https://github.com/zlindner\n[@marcustut]: https://github.com/marcustut\n[@rakshith-ravi]: https://github.com/rakshith-ravi\n[@bradfier]: https://github.com/bradfier\n[@fuzzbuck]: https://github.com/fuzzbuck\n[@cycraig]: https://github.com/cycraig\n[@fasterthanlime]: https://github.com/fasterthanlime\n[@he4d]: https://github.com/he4d\n[@DXist]: https://github.com/DXist\n[@Wopple]: https://github.com/Wopple\n[@TravisWhitehead]: https://github.com/TravisWhitehead\n[@ThibsG]: https://github.com/ThibsG\n[@rongcuid]: https://github.com/rongcuid\n[@moatra]: https://github.com/moatra\n[@penberg]: https://github.com/penberg\n[@saiintbrisson]: https://github.com/saiintbrisson\n[@FSMaxB]: https://github.com/FSMaxB\n[@95ulisse]: https://github.com/95ulisse\n[@miles170]: https://github.com/miles170\n[@ar3s3ru]: https://github.com/ar3s3ru\n[@cdbfoster]: https://github.com/cdbfoster\n[@andyquinterom]: https://github.com/andyquinterom\n[@CosmicHorrorDev]: https://github.com/CosmicHorrorDev\n[@VictorKoenders]: https://github.com/VictorKoenders\n[@joehillen]: https://github.com/joehillen\n[@OverHash]: https://github.com/OverHash\n[@laundmo]: https://github.com/laundmo\n[@nbaztec]: https://github.com/nbaztec\n[@bgeron]: https://github.com/bgeron\n[@benesch]: https://github.com/benesch\n[@nstinus]: https://github.com/nstinus\n[@grgi]: https://github.com/grgi\n[@sergeiivankov]: https://github.com/sergeiivankov\n[@jaysonsantos]: https://github.com/jaysonsantos\n[@dbrgn]: https://github.com/dbrgn\n[@grantkee]: https://github.com/grantkee\n[@bnoctis]: https://github.com/bnoctis\n[@aschey]: https://github.com/aschey\n[@df51d]: https://github.com/df51d\n[@codahale]: https://github.com/codahale\n[@arlyon]: https://github.com/arlyon\n[@SergioBenitez]: https://github.com/SergioBenitez\n[@tgeoghegan]: https://github.com/tgeoghegan\n[@vizvasrj]: https://github.com/vizvasrj\n[@phlip9]: https://github.com/phlip9\n[@MidasLamb]: https://github.com/MidasLamb\n[@utkarshgupta137]: https://github.com/utkarshgupta137\n[@Arcayr]: https://github.com/Arcayr\n[@mdecimus]: https://github.com/mdecimus\n[@Razican]: https://github.com/Razican\n[@southball]: https://github.com/southball\n[@alilleybrinker]: https://github.com/alilleybrinker\n[@titaniumtraveler]: https://github.com/titaniumtraveler\n[@nyurik]: https://github.com/nyurik\n[@stepantubanov]: https://github.com/stepantubanov\n[@iamquang95]: https://github.com/iamquang95\n[@jnnnnn]: https://github.com/jnnnnn\n[@saolof]: https://github.com/saolof\n[@deneut]: https://github.com/deneut\n[@kitterion]: https://github.com/kitterion\n[@denschub]: https://github.com/denschub\n[@fd]: https://github.com/fd\n[@mrl5]: https://github.com/mrl5\n[@Xydez]: https://github.com/Xydez\n[@vabka]: https://github.com/vabka\n[@ldanilek]: https://github.com/ldanilek\n[@inahga]: https://github.com/inahga\n[@JockeM]: https://github.com/JockeM\n[@vmax]: https://github.com/vmax\n[@sebastianv89]: https://github.com/sebastianv89\n[@marcusirgens]: https://github.com/marcusirgens\n[@tsing]: https://github.com/tsing\n[@snf]: https://github.com/snf\n[@wyhaya]: https://github.com/wyhaya\n[@hakoerber]: https://github.com/hakoerber\n[@olback]: https://github.com/olback\n[@kryptan]: https://github.com/kryptan\n[@grant0417]: https://github.com/grant0417\n[@fermanjj]: https://github.com/fermanjj\n[@grooverdan]: https://github.com/grooverdan\n[@bobozaur]: https://github.com/bobozaur\n[@aldur]: https://github.com/aldur\n[@hgranthorner]: https://github.com/hgranthorner\n[@ripa1995]: https://github.com/ripa1995\n[@fhsgoncalves]: https://github.com/fhsgoncalves\n[@uttarayan21]: https://github.com/uttarayan21\n[@tk2217]: https://github.com/tk2217\n[@hamiltop]: https://github.com/hamiltop\n[@cameronbraid]: https://github.com/cameronbraid\n[@Baptistemontan]: https://github.com/Baptistemontan\n[@satwanjyu]: https://github.com/satwanjyu\n[@boris-lok]: https://github.com/boris-lok\n[@qwerty2501]: https://github.com/qwerty2501\n[@Nemo157]: https://github.com/Nemo157\n[@snspinn]: https://github.com/snspinn\n[@granddaifuku]: https://github.com/granddaifuku\n[@yasamoka]: https://github.com/yasamoka\n[@mattfbacon]: https://github.com/mattfbacon\n[@A248]: https://github.com/A248\n[@conradludgate]: https://github.com/conradludgate\n[@anupj]: https://github.com/anupj\n[@nanoqsh]: https://github.com/nanoqsh\n[@brianheineman]: https://github.com/brianheineman\n[@jkleinknox]: https://github.com/jkleinknox\n[@cryeprecision]: https://github.com/cryeprecision\n[@Vrajs16]: https://github.com/Vrajs16\n[@shiftrightonce]: https://github.com/shiftrightonce\n[@tamasfe]: https://github.com/tamasfe\n[@lily-mosquitoes]: https://github.com/lily-mosquitoes\n[@larsschumacher]: https://github.com/larsschumacher\n[@shengsheng]: https://github.com/shengsheng\n[@Fyko]: https://github.com/Fyko\n[@kshramt]: https://github.com/kshramt\n[@Dawsoncodes]: https://github.com/Dawsoncodes\n[@tadghh]: https://github.com/tadghh\n[@holicc]: https://github.com/holicc\n[@takenoko-gohan]: https://github.com/takenoko-gohan\n[@iangilfillan]: https://github.com/iangilfillan\n[@iamjpotts]: https://github.com/iamjpotts\n[@Icerath]: https://github.com/Icerath\n[@pawurb]: https://github.com/pawurb\n[@darkecho731]: https://github.com/darkecho731\n[@mirek26]: https://github.com/mirek26\n[@Ekleog]: https://github.com/Ekleog\n[@zoomiti]: https://github.com/zoomiti\n[@ciffelia]: https://github.com/ciffelia\n[@rafaelGuerreiro]: https://github.com/rafaelGuerreiro\n[@alu]: https://github.com/alu\n[@BadBastion]: https://github.com/BadBastion\n[@tylerhawkes]: https://github.com/tylerhawkes\n[@g-bartoszek]: https://github.com/g-bartoszek\n[@benluelo]: https://github.com/benluelo\n[@ralpha]: https://github.com/ralpha\n[@nitn3lav]: https://github.com/nitn3lav\n[@FlakM]: https://github.com/FlakM\n[@hoxxep]: https://github.com/hoxxep\n[@NfNitLoop]: https://github.com/NfNitLoop\n[@GnomedDev]: https://github.com/GnomedDev\n[@pxp9]: https://github.com/pxp9\n[@RaghavRox]: https://github.com/RaghavRox\n[@cleverjam]: https://github.com/cleverjam\n[@BlackSoulHub]: https://github.com/BlackSoulHub\n[@levkk]: https://github.com/levkk\n[@danjpgriffin]: https://github.com/danjpgriffin\n[@toxeus]: https://github.com/toxeus\n[@jasonish]: https://github.com/jasonish\n[@AlphaKeks]: https://github.com/AlphaKeks\n[@Zarathustra2]: https://github.com/Zarathustra2\n[@gridbox]: https://github.com/gridbox\n[@joelkoen]: https://github.com/joelkoen\n[@nk9]: https://github.com/nk9\n[@etorreborre]: https://github.com/etorreborre\n[@LecrisUT]: https://github.com/LecrisUT\n[@JohannesIBK]: https://github.com/JohannesIBK\n[@Lachstec]: https://github.com/Lachstec\n[@SrGesus]: https://github.com/SrGesus\n[@CommanderStorm]: https://github.com/CommanderStorm\n[@hamirmahal]: https://github.com/hamirmahal\n[@DirectorX]: https://github.com/DirectorX\n[@KobusEllis]: https://github.com/KobusEllis\n[@YgorSouza]: https://github.com/YgorSouza\n[@Zarthus]: https://github.com/Zarthus\n[@ckampfe]: https://github.com/ckampfe\n[@tottoto]: https://github.com/tottoto\n[@ods]: https://github.com/ods\n[@soucosmo]: https://github.com/soucosmo\n[@kolinfluence]: https://github.com/kolinfluence\n[@joeydewaal]: https://github.com/joeydewaal\n[@pierre-wehbe]: https://github.com/pierre-wehbe\n[@carschandler]: https://github.com/carschandler\n[@kdesjard]: https://github.com/kdesjard\n[@luveti]: https://github.com/luveti\n[@dojiong]: https://github.com/dojiong\n[@jayvdb]: https://github.com/jayvdb\n[@kurtbuilds]: https://github.com/kurtbuilds\n[@lilydjwg]: https://github.com/lilydjwg\n[@M3t0r]: https://github.com/M3t0r\n[@vsuryamurthy]: https://github.com/vsuryamurthy\n[@manifest]: https://github.com/manifest\n[@tbar4]: https://github.com/tbar4\n[@sandhose]: https://github.com/sandhose\n[@IlyaBizyaev]: https://github.com/IlyaBizyaev\n[@philipcristiano]: https://github.com/philipcristiano\n[@xuehaonan27]: https://github.com/xuehaonan27\n[@chanks]: https://github.com/chanks\n[@Ddystopia]: https://github.com/Ddystopia\n[@veigaribo]: https://github.com/veigaribo\n[@Norlock]: https://github.com/Norlock\n[@swlynch99]: https://github.com/swlynch99\n[@BenoitRanque]: https://github.com/BenoitRanque\n[@hsivonen]: https://github.com/hsivonen\n[@andreweggleston]: https://github.com/andreweggleston\n[@Suficio]: https://github.com/Suficio\n[@bonega]: https://github.com/bonega\n[@nico-incubiq]: https://github.com/nico-incubiq\n[@tisonkun]: https://github.com/tisonkun\n[@karambarakat]: https://github.com/karambarakat\n[@seanaye]: https://github.com/seanaye\n[@remysaissy]: https://github.com/remysaissy\n[@BeauGieskens]: https://github.com/BeauGieskens\n[@Turbo87]: https://github.com/Turbo87\n[@jthacker]: https://github.com/jthacker\n[@benwilber]: https://github.com/benwilber\n[@chitoku-k]: https://github.com/chitoku-k\n[@chanmaoganda]: https://github.com/chanmaoganda\n[@dns2utf8]: https://github.com/dns2utf8\n[@mattrighetti]: https://github.com/mattrighetti\n[@soulwa]: https://github.com/soulwa\n[@kildrens]: https://github.com/kildrens\n[@xvapx]: https://github.com/xvapx\n[@jonasmalacofilho]: https://github.com/jonasmalacofilho\n[@sulami]: https://github.com/sulami\n[@thriller08]: https://github.com/thriller08\n[@mbj]: https://github.com/mbj\n[@TeCHiScy]: https://github.com/TeCHiScy\n[@mpyw]: https://github.com/mpyw\n[@bonsairobo]: https://github.com/bonsairobo\n[@gferon]: https://github.com/gferon\n[@joshka]: https://github.com/joshka\n[@kujeger]: https://github.com/kujeger\n[@dyc3]: https://github.com/dyc3\n[@ThomWright]: https://github.com/ThomWright\n[@duhby]: https://github.com/duhby\n[@V02460]: https://github.com/V02460\n[@nipunn1313]: https://github.com/nipunn1313\n[@miniduikboot]: https://github.com/miniduikboot\n[@0xfourzerofour]: https://github.com/0xfourzerofour\n[@AlexTMjugador]: https://github.com/AlexTMjugador\n[@martin-kolarik]: https://github.com/martin-kolarik\n[@cvzx]: https://github.com/cvzx\n[@Dirbaio]: https://github.com/Dirbaio\n[@elichai]: https://github.com/elichai\n[@silvestrpredko]: https://github.com/silvestrpredko\n[@davidcornu]: https://github.com/davidcornu\n[@zebrapurring]: https://github.com/zebrapurring\n[@djarb]: https://github.com/djarb\n[@barskern]: https://github.com/barskern\n[@nhatcher-frequenz]: https://github.com/nhatcher-frequenz\n[@JerryQ17]: https://github.com/JerryQ17\n[@jpmelos]: https://github.com/jpmelos\n[@psionic-k]: https://github.com/psionic-k\n[@Xiretza]: https://github.com/Xiretza\n[@2ndDerivative]: https://github.com/2ndDerivative\n[@kevincox]: https://github.com/kevincox\n[@papaj-na-wrotkach]: https://github.com/papaj-na-wrotkach\n[@xb284524239]: https://github.com/xb284524239\n[@Dosenpfand]: https://github.com/Dosenpfand\n[@daviduebler]: https://github.com/daviduebler\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nSo, you've decided to contribute, that's great!\n\nYou can use this document to figure out how and where to start.\n\n## Getting started\n\n- Make sure you have a [GitHub account](https://github.com/join).\n- Take a look at [existing issues](https://github.com/launchbadge/sqlx/issues).\n- If you need to create an issue:\n  - Make sure to clearly describe it.\n  - Including steps to reproduce when it is a bug.\n  - Include the version of SQLx used.\n  - Include the database driver and version.\n  - Include the database version.\n\n## Making changes\n\n- Fork the repository on GitHub.\n- Create a branch on your fork.\n  - You can usually base it on the `main` branch.\n  - Make sure not to commit directly to `main`.\n- Make commits of logical and atomic units.\n- Make sure you have added the necessary tests for your changes.\n- Push your changes to a topic branch in your fork of the repository.\n- Submit a pull request to the original repository.\n\n## What to work on\n\nWe try to mark issues with a suggested level of experience (in Rust/SQL/SQLx).\nWhere possible we try to spell out how to go about implementing the feature.\n\nTo start with, check out:\n- Issues labeled as [\"good first issue\"](https://github.com/launchbadge/sqlx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).\n- Issues labeled as [\"Easy\"](https://github.com/launchbadge/sqlx/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy).\n\nAdditionally, it's always good to work on improving/adding examples and documentation.\n\n## Communication\n\nIf you're unsure about your contribution or simply want to ask a question about anything, you can:\n- Visit the [SQLx Discord server](https://discord.gg/uuruzJ7)\n- Discuss something directly in the [Github issue](https://github.com/launchbadge/sqlx/issues).\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\n    \".\",\n    \"sqlx-core\",\n    \"sqlx-macros\",\n    \"sqlx-macros-core\",\n    \"sqlx-test\",\n    \"sqlx-cli\",\n    #    \"sqlx-bench\",\n    \"sqlx-mysql\",\n    \"sqlx-postgres\",\n    \"sqlx-sqlite\",\n    \"examples/mysql/todos\",\n    \"examples/postgres/axum-social-with-tests\",\n    \"examples/postgres/chat\",\n    \"examples/postgres/files\",\n    \"examples/postgres/json\",\n    \"examples/postgres/listen\",\n    \"examples/postgres/mockable-todos\",\n    \"examples/postgres/multi-database\",\n    \"examples/postgres/multi-tenant\",\n    \"examples/postgres/preferred-crates\",\n    \"examples/postgres/todos\",\n    \"examples/postgres/transaction\",\n    \"examples/sqlite/todos\",\n    \"examples/sqlite/extension\",\n]\n\n[workspace.package]\nversion = \"0.9.0-alpha.1\"\nlicense = \"MIT OR Apache-2.0\"\n# TODO: upgrade to edition 2024 (after merging all pending PRs)\nedition = \"2021\"\nrepository = \"https://github.com/launchbadge/sqlx\"\nkeywords = [\"database\", \"async\", \"postgres\", \"mysql\", \"sqlite\"]\ncategories = [\"database\", \"asynchronous\"]\nauthors = [\n    \"Ryan Leckey <leckey.ryan@gmail.com>\",\n    \"Austin Bonander <austin.bonander@gmail.com>\",\n    \"Chloe Ross <orangesnowfox@gmail.com>\",\n    \"Daniel Akhterov <akhterovd@gmail.com>\",\n]\nrust-version = \"1.86.0\"\n\n[package]\nname = \"sqlx\"\nreadme = \"README.md\"\ndocumentation = \"https://docs.rs/sqlx\"\ndescription = \"🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n# Note: written so that it may be copy-pasted to other crates\n[package.metadata.docs.rs]\nfeatures = [\"_unstable-docs\"]\nrustdoc-args = [\"--cfg\", \"docsrs\"]\n\n[features]\ndefault = [\"any\", \"macros\", \"migrate\", \"json\"]\n\nderive = [\"sqlx-macros/derive\"]\nmacros = [\"derive\", \"sqlx-macros/macros\", \"sqlx-core/offline\", \"sqlx-mysql?/offline\", \"sqlx-postgres?/offline\", \"sqlx-sqlite?/offline\"]\nmigrate = [\"sqlx-core/migrate\", \"sqlx-macros?/migrate\", \"sqlx-mysql?/migrate\", \"sqlx-postgres?/migrate\", \"sqlx-sqlite?/migrate\"]\n\n# Enable parsing of `sqlx.toml` for configuring macros and migrations.\nsqlx-toml = [\"sqlx-core/sqlx-toml\", \"sqlx-macros?/sqlx-toml\", \"sqlx-sqlite?/sqlx-toml\"]\n\n# intended mainly for CI and docs\nall-databases = [\"mysql\", \"sqlite\", \"postgres\", \"any\"]\n_unstable-all-types = [\n    \"bigdecimal\",\n    \"rust_decimal\",\n    \"json\",\n    \"time\",\n    \"chrono\",\n    \"ipnet\",\n    \"ipnetwork\",\n    \"mac_address\",\n    \"uuid\",\n    \"bit-vec\",\n    \"bstr\"\n]\n\n# Render documentation that wouldn't otherwise be shown (e.g. `sqlx_core::config`).\n_unstable-docs = [\n    \"all-databases\",\n    \"_unstable-all-types\",\n    \"sqlx-sqlite/_unstable-docs\"\n]\n\n# Base runtime features without TLS\nruntime-async-global-executor = [\"_rt-async-global-executor\", \"sqlx-core/_rt-async-global-executor\", \"sqlx-macros?/_rt-async-global-executor\"]\nruntime-async-std = [\"_rt-async-std\", \"sqlx-core/_rt-async-std\", \"sqlx-macros?/_rt-async-std\"]\nruntime-smol = [\"_rt-smol\", \"sqlx-core/_rt-smol\", \"sqlx-macros?/_rt-smol\"]\nruntime-tokio = [\"_rt-tokio\", \"sqlx-core/_rt-tokio\", \"sqlx-macros?/_rt-tokio\"]\n\n# TLS features\ntls-native-tls = [\"sqlx-core/_tls-native-tls\", \"sqlx-macros?/_tls-native-tls\"]\ntls-rustls = [\"tls-rustls-ring\"] # For backwards compatibility\ntls-rustls-aws-lc-rs = [\"sqlx-core/_tls-rustls-aws-lc-rs\", \"sqlx-macros?/_tls-rustls-aws-lc-rs\"]\ntls-rustls-ring = [\"tls-rustls-ring-webpki\"] # For backwards compatibility\ntls-rustls-ring-webpki = [\"sqlx-core/_tls-rustls-ring-webpki\", \"sqlx-macros?/_tls-rustls-ring-webpki\"]\ntls-rustls-ring-native-roots = [\"sqlx-core/_tls-rustls-ring-native-roots\", \"sqlx-macros?/_tls-rustls-ring-native-roots\"]\n\n# No-op feature used by the workflows to compile without TLS enabled. Not meant for general use.\ntls-none = []\n\n# for conditional compilation\n_rt-async-global-executor = []\n_rt-async-std = []\n_rt-smol = []\n_rt-tokio = []\n_sqlite = []\n\n# database\nany = [\"sqlx-core/any\", \"sqlx-mysql?/any\", \"sqlx-postgres?/any\", \"sqlx-sqlite?/any\"]\npostgres = [\"sqlx-postgres\", \"sqlx-macros?/postgres\"]\nmysql = [\"sqlx-mysql\", \"sqlx-macros?/mysql\"]\nsqlite = [\"sqlite-bundled\", \"sqlite-deserialize\", \"sqlite-load-extension\", \"sqlite-unlock-notify\"]\n\n# SQLite base features\nsqlite-bundled = [\"_sqlite\", \"sqlx-sqlite/bundled\", \"sqlx-macros?/sqlite\"]\nsqlite-unbundled = [\"_sqlite\", \"sqlx-sqlite/unbundled\", \"sqlx-macros?/sqlite-unbundled\"]\n\n# SQLite features using conditionally compiled APIs\n# Note: these assume `sqlite-bundled` or `sqlite-unbundled` is also enabled\n#\n# Enable `SqliteConnection::deserialize()` and `::serialize()`\n# Cannot be used with `-DSQLITE_OMIT_DESERIALIZE`; requires `-DSQLITE_ENABLE_DESERIALIZE` on SQLite < 3.36.0\nsqlite-deserialize = [\"sqlx-sqlite/deserialize\"]\n\n# Enable `SqliteConnectOptions::extension()` and `::extension_with_entrypoint()`.\n# Also required to use `drivers.sqlite.unsafe-load-extensions` from `sqlx.toml`.\n# Cannot be used with `-DSQLITE_OMIT_LOAD_EXTENSION`\nsqlite-load-extension = [\"sqlx-sqlite/load-extension\", \"sqlx-macros?/sqlite-load-extension\"]\n\n# Enables `sqlite3_preupdate_hook`\n# Requires `-DSQLITE_ENABLE_PREUPDATE_HOOK` (set automatically with `sqlite-bundled`)\nsqlite-preupdate-hook = [\"sqlx-sqlite/preupdate-hook\"]\n\n# Enable internal handling of `SQLITE_LOCKED_SHAREDCACHE`\n# Requires `-DSQLITE_ENABLE_UNLOCK_NOTIFY` (set automatically with `sqlite-bundled`)\nsqlite-unlock-notify = [\"sqlx-sqlite/unlock-notify\"]\n\n# types\njson = [\"sqlx-core/json\", \"sqlx-macros?/json\", \"sqlx-mysql?/json\", \"sqlx-postgres?/json\", \"sqlx-sqlite?/json\"]\n\nbigdecimal = [\"sqlx-core/bigdecimal\", \"sqlx-macros?/bigdecimal\", \"sqlx-mysql?/bigdecimal\", \"sqlx-postgres?/bigdecimal\"]\nbit-vec = [\"sqlx-core/bit-vec\", \"sqlx-macros?/bit-vec\", \"sqlx-postgres?/bit-vec\"]\nchrono = [\"sqlx-core/chrono\", \"sqlx-macros?/chrono\", \"sqlx-mysql?/chrono\", \"sqlx-postgres?/chrono\", \"sqlx-sqlite?/chrono\"]\nipnet = [\"sqlx-core/ipnet\", \"sqlx-macros?/ipnet\", \"sqlx-postgres?/ipnet\"]\nipnetwork = [\"sqlx-core/ipnetwork\", \"sqlx-macros?/ipnetwork\", \"sqlx-postgres?/ipnetwork\"]\nmac_address = [\"sqlx-core/mac_address\", \"sqlx-macros?/mac_address\", \"sqlx-postgres?/mac_address\"]\nrust_decimal = [\"sqlx-core/rust_decimal\", \"sqlx-macros?/rust_decimal\", \"sqlx-mysql?/rust_decimal\", \"sqlx-postgres?/rust_decimal\"]\ntime = [\"sqlx-core/time\", \"sqlx-macros?/time\", \"sqlx-mysql?/time\", \"sqlx-postgres?/time\", \"sqlx-sqlite?/time\"]\nuuid = [\"sqlx-core/uuid\", \"sqlx-macros?/uuid\", \"sqlx-mysql?/uuid\", \"sqlx-postgres?/uuid\", \"sqlx-sqlite?/uuid\"]\nregexp = [\"sqlx-sqlite?/regexp\"]\nbstr = [\"sqlx-core/bstr\"]\n\n[workspace.dependencies]\n# Core Crates\nsqlx-core = { version = \"=0.9.0-alpha.1\", path = \"sqlx-core\" }\nsqlx-macros-core = { version = \"=0.9.0-alpha.1\", path = \"sqlx-macros-core\" }\nsqlx-macros = { version = \"=0.9.0-alpha.1\", path = \"sqlx-macros\" }\n\n# Driver crates\nsqlx-mysql = { version = \"=0.9.0-alpha.1\", path = \"sqlx-mysql\" }\nsqlx-postgres = { version = \"=0.9.0-alpha.1\", path = \"sqlx-postgres\" }\nsqlx-sqlite = { version = \"=0.9.0-alpha.1\", path = \"sqlx-sqlite\" }\n\n# Facade crate (for reference from sqlx-cli)\nsqlx = { version = \"=0.9.0-alpha.1\", path = \".\", default-features = false }\n\n# Common type integrations shared by multiple driver crates.\n# These are optional unless enabled in a workspace crate.\nbigdecimal = \"0.4.0\"\nbit-vec = \"0.8\"\nchrono = { version = \"0.4.34\", default-features = false, features = [\"std\", \"clock\"] }\nipnet = \"2.3.0\"\nipnetwork = \"0.21.1\"\nmac_address = \"1.1.5\"\nrust_decimal = { version = \"1.26.1\", default-features = false, features = [\"std\"] }\ntime = { version = \"0.3.36\", features = [\"formatting\", \"parsing\", \"macros\"] }\nuuid = \"1.1.2\"\n\n# Common utility crates\ncfg-if = \"1.0.0\"\ndotenvy = { version = \"0.15.0\", default-features = false }\nthiserror = { version = \"2.0.17\", default-features = false, features = [\"std\"] }\n\n# Runtimes\n[workspace.dependencies.async-global-executor]\nversion = \"3.1\"\ndefault-features = false\nfeatures = [\"async-io\"]\n\n[workspace.dependencies.async-std]\nversion = \"1.13\"\n\n[workspace.dependencies.smol]\nversion = \"2.0\"\ndefault-features = false\n\n[workspace.dependencies.tokio]\nversion = \"1\"\nfeatures = [\"time\", \"net\", \"sync\", \"fs\", \"io-util\", \"rt\"]\ndefault-features = false\n\n[dependencies]\nsqlx-core = { workspace = true, features = [\"migrate\"] }\nsqlx-macros = { workspace = true, optional = true }\n\nsqlx-mysql = { workspace = true, optional = true }\nsqlx-postgres = { workspace = true, optional = true }\nsqlx-sqlite = { workspace = true, optional = true }\n\n[dev-dependencies]\nanyhow = \"1.0.52\"\ntime_ = { version = \"0.3.2\", package = \"time\" }\nfutures-util = { version = \"0.3.19\", default-features = false, features = [\"alloc\"] }\nenv_logger = \"0.11\"\nasync-std = { workspace = true, features = [\"attributes\"] }\ntokio = { version = \"1.15.0\", features = [\"full\"] }\ndotenvy = \"0.15.0\"\ntrybuild = \"1.0.53\"\nsqlx-test = { path = \"./sqlx-test\" }\npaste = \"1.0.6\"\nserde = { version = \"1.0.132\", features = [\"derive\"] }\nserde_json = \"1.0.73\"\nurl = \"2.2.2\"\nrand = \"0.8.4\"\nrand_xoshiro = \"0.6.0\"\nhex = \"0.4.3\"\ntempfile = \"3.10.1\"\ncriterion = { version = \"0.5.1\", features = [\"async_tokio\"] }\nlibsqlite3-sys = { version = \"0.30.1\" }\n\n# If this is an unconditional dev-dependency then Cargo will *always* try to build `libsqlite3-sys`,\n# even when SQLite isn't the intended test target, and fail if the build environment is not set up for compiling C code.\n[target.'cfg(sqlite_test_sqlcipher)'.dev-dependencies]\n# Enable testing with SQLCipher if specifically requested.\nlibsqlite3-sys = { version = \"0.30.1\", features = [\"bundled-sqlcipher\"] }\n\n# Common lint settings for the workspace\n[workspace.lints.clippy]\n# https://github.com/launchbadge/sqlx/issues/3440\ncast_possible_truncation = 'deny'\ncast_possible_wrap = 'deny'\ncast_sign_loss = 'deny'\n# See `clippy.toml`\ndisallowed_methods = 'deny'\n\n\n[lints.rust.unexpected_cfgs]\nlevel = 'warn'\ncheck-cfg = [\n    'cfg(mariadb, values(any()))',\n    'cfg(postgres, values(any()))',\n    'cfg(sqlite_ipaddr)',\n    'cfg(sqlite_test_sqlcipher)',\n]\n\n#\n# Any\n#\n\n[[test]]\nname = \"any\"\npath = \"tests/any/any.rs\"\nrequired-features = [\"any\"]\n\n[[test]]\nname = \"any-pool\"\npath = \"tests/any/pool.rs\"\nrequired-features = [\"any\"]\n\n#\n# Migrations\n#\n\n[[test]]\nname = \"migrate-macro\"\npath = \"tests/migrate/macro.rs\"\nrequired-features = [\"macros\", \"migrate\"]\n\n#\n# SQLite\n#\n\n[[test]]\nname = \"sqlite\"\npath = \"tests/sqlite/sqlite.rs\"\nrequired-features = [\"sqlite\"]\n\n[[test]]\nname = \"sqlite-any\"\npath = \"tests/sqlite/any.rs\"\nrequired-features = [\"sqlite\"]\n\n[[test]]\nname = \"sqlite-types\"\npath = \"tests/sqlite/types.rs\"\nrequired-features = [\"sqlite\"]\n\n[[test]]\nname = \"sqlite-describe\"\npath = \"tests/sqlite/describe.rs\"\nrequired-features = [\"sqlite\"]\n\n[[test]]\nname = \"sqlite-macros\"\npath = \"tests/sqlite/macros.rs\"\nrequired-features = [\"_sqlite\", \"macros\"]\n\n[[test]]\nname = \"sqlite-derives\"\npath = \"tests/sqlite/derives.rs\"\nrequired-features = [\"sqlite\", \"macros\"]\n\n[[test]]\nname = \"sqlite-error\"\npath = \"tests/sqlite/error.rs\"\nrequired-features = [\"sqlite\"]\n\n[[test]]\nname = \"sqlite-sqlcipher\"\npath = \"tests/sqlite/sqlcipher.rs\"\nrequired-features = [\"sqlite\"]\n\n[[test]]\nname = \"sqlite-test-attr\"\npath = \"tests/sqlite/test-attr.rs\"\nrequired-features = [\"sqlite\", \"macros\", \"migrate\"]\n\n[[test]]\nname = \"sqlite-migrate\"\npath = \"tests/sqlite/migrate.rs\"\nrequired-features = [\"sqlite\", \"macros\", \"migrate\"]\n\n[[test]]\nname = \"sqlite-rustsec\"\npath = \"tests/sqlite/rustsec.rs\"\nrequired-features = [\"sqlite\"]\n\n[[bench]]\nname = \"sqlite-describe\"\npath = \"benches/sqlite/describe.rs\"\nharness = false\nrequired-features = [\"sqlite\"]\n\n#\n# MySQL\n#\n\n[[test]]\nname = \"mysql\"\npath = \"tests/mysql/mysql.rs\"\nrequired-features = [\"mysql\"]\n\n[[test]]\nname = \"mysql-types\"\npath = \"tests/mysql/types.rs\"\nrequired-features = [\"mysql\"]\n\n[[test]]\nname = \"mysql-describe\"\npath = \"tests/mysql/describe.rs\"\nrequired-features = [\"mysql\"]\n\n[[test]]\nname = \"mysql-derives\"\npath = \"tests/mysql/derives.rs\"\nrequired-features = [\"mysql\", \"derive\"]\n\n[[test]]\nname = \"mysql-macros\"\npath = \"tests/mysql/macros.rs\"\nrequired-features = [\"mysql\", \"macros\"]\n\n[[test]]\nname = \"mysql-error\"\npath = \"tests/mysql/error.rs\"\nrequired-features = [\"mysql\"]\n\n[[test]]\nname = \"mysql-test-attr\"\npath = \"tests/mysql/test-attr.rs\"\nrequired-features = [\"mysql\", \"macros\", \"migrate\"]\n\n[[test]]\nname = \"mysql-migrate\"\npath = \"tests/mysql/migrate.rs\"\nrequired-features = [\"mysql\", \"macros\", \"migrate\"]\n\n[[test]]\nname = \"mysql-rustsec\"\npath = \"tests/mysql/rustsec.rs\"\nrequired-features = [\"mysql\"]\n\n#\n# PostgreSQL\n#\n\n[[test]]\nname = \"postgres\"\npath = \"tests/postgres/postgres.rs\"\nrequired-features = [\"postgres\"]\n\n[[test]]\nname = \"postgres-types\"\npath = \"tests/postgres/types.rs\"\nrequired-features = [\"postgres\"]\n\n[[test]]\nname = \"postgres-describe\"\npath = \"tests/postgres/describe.rs\"\nrequired-features = [\"postgres\"]\n\n[[test]]\nname = \"postgres-macros\"\npath = \"tests/postgres/macros.rs\"\nrequired-features = [\"postgres\", \"macros\"]\n\n[[test]]\nname = \"postgres-derives\"\npath = \"tests/postgres/derives.rs\"\nrequired-features = [\"postgres\", \"macros\"]\n\n[[test]]\nname = \"postgres-error\"\npath = \"tests/postgres/error.rs\"\nrequired-features = [\"postgres\"]\n\n[[test]]\nname = \"postgres-test-attr\"\npath = \"tests/postgres/test-attr.rs\"\nrequired-features = [\"postgres\", \"macros\", \"migrate\"]\n\n[[test]]\nname = \"postgres-migrate\"\npath = \"tests/postgres/migrate.rs\"\nrequired-features = [\"postgres\", \"macros\", \"migrate\"]\n\n[[test]]\nname = \"postgres-query-builder\"\npath = \"tests/postgres/query_builder.rs\"\nrequired-features = [\"postgres\"]\n\n[[test]]\nname = \"postgres-rustsec\"\npath = \"tests/postgres/rustsec.rs\"\nrequired-features = [\"postgres\", \"macros\", \"migrate\"]\n"
  },
  {
    "path": "FAQ.md",
    "content": "SQLx Frequently Asked Questions\n===============================\n\n### What database versions does SQLx support?\n\nThis is a difficult question to answer because it depends on which features of the databases are used and when those features were introduced. SQL databases tend to be very strongly backwards-compatible so it's likely that SQLx will work with some very old versions. \n\nTLS support is one of the features that ages most quickly with databases, since old SSL/TLS versions are deprecated over time as they become insecure due to weaknesses being discovered; this is especially important to consider when using RusTLS, as it only supports the latest TLS version for security reasons (see the question below mentioning RusTLS for details).\n\nAs a rule, however, we only officially support the range of versions for each database that are still actively maintained, and will drop support for versions as they reach their end-of-life.\n\n* Postgres has a page to track these versions and give their end-of-life dates: https://www.postgresql.org/support/versioning/\n* MariaDB has a similar list here (though it doesn't show the dates at which old versions were EOL'd): https://mariadb.com/kb/en/mariadb-server-release-dates/\n* MySQL's equivalent page is more concerned with what platforms are supported by the newest and oldest maintained versions: https://www.mysql.com/support/supportedplatforms/database.html\n    * However, its Wikipedia page helpfully tracks its versions and their announced EOL dates: https://en.wikipedia.org/wiki/MySQL#Release_history\n* SQLite is easy as only SQLite 3 is supported and the current version depends on the version of the `libsqlite3-sys` crate being used.\n\nFor each database and where applicable, we test against the latest and oldest versions that we intend to support. You can see the current versions being tested against by looking at our CI config: https://github.com/launchbadge/sqlx/blob/main/.github/workflows/sqlx.yml#L168\n\n-------------------------------------------------------------------\n<a name=\"MSRV\"></a>\n### What versions of Rust does SQLx support? What is SQLx's MSRV\\*?\n\nSQLx's MSRV is the second-to-latest stable release as of the beginning of the current release cycle (`0.x.0`).\nIt will remain there until the next major release (`0.{x + 1}.0`).\n\nFor example, as of the `0.8.0` release of SQLx, the latest stable Rust version was `1.79.0`, so the MSRV for the\n`0.8.x` release cycle of SQLx is `1.78.0`.\n\nThis guarantees that SQLx will compile with a Rust version that is _at least_ six weeks old, which should be plenty\nof time for it to make it through any packaging system that is being actively kept up to date.\n\nWe do _not_ recommend installing Rust through operating system packages, \nas they can often be a whole year or more out-of-date.\n\n\\*Minimum Supported Rust Version\n\n[`rust-version`]: https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-rust-version-field\n\n----------------------------------------------------------------\n\n### Can SQLx Add Support for New Databases?\n\nWe are always open to discuss adding support for new databases, but as of writing, have no plans to in the short term.\n\nImplementing support for a new database in SQLx is a _huge_ lift. Expecting this work to be done for free is highly unrealistic.  \nIn all likelihood, the implementation would need to be written from scratch.  \nEven if Rust bindings exist, they may not support `async`.  \nEven if they support `async`, they may only support either Tokio or `async-std`, and not both.  \nEven if they support Tokio and `async-std`, the API may not be flexible enough or provide sufficient information (e.g. for implementing the macros).\n\nIf we have to write the implementation from scratch, is the protocol publicly documented, and stable?\n\nEven if everything is supported on the client side, how will we run tests against the database? Is it open-source, or proprietary? Will it require a paid license?\n\nFor example, Oracle Database's protocol is proprietary and only supported through their own libraries, which do not support Rust, and only have blocking APIs (see: [Oracle Call Interface for C](https://docs.oracle.com/en/database/oracle/oracle-database/23/lnoci/index.html)).\nThis makes it a poor candidate for an async-native crate like SQLx--though we support SQLite, which also only has a blocking API, that's the exception and not the rule. Wrapping blocking APIs is not very scalable.\n\nWe still have plans to bring back the MSSQL driver, but this is not feasible as of writing with the current maintenance workload. Should this change, an announcement will be made on Github as well as our [Discord server](https://discord.gg/uuruzJ7).\n\n### What If I'm Willing to Contribute the Implementation?\n\nBeing willing to contribute an implementation for a new database is one thing, but there's also the ongoing maintenance burden to consider.\n\nAre you willing to provide support long-term?  \nWill there be enough users that we can rely on outside contributions?  \nOr is support going to fall to the current maintainer(s)?\n\nThis is the kind of thing that will need to be supported in SQLx _long_ after the initial implementation, or else later need to be removed.\nIf you don't have plans for how to support a new driver long-term, then it doesn't belong as part of SQLx itself.\n\nHowever, drivers don't necessarily need to live _in_ SQLx anymore. Since 0.7.0, drivers don't need to be compiled-in to be functional.\nSupport for third-party drivers in `sqlx-cli` and the `query!()` macros is pending, as well as documenting the process of writing a driver, but contributions are welcome in this regard.\n\nFor example, see [sqlx-exasol](https://crates.io/crates/sqlx-exasol).\n\n----------------------------------------------------------------\n### Can SQLx Add Support for New Data-Type Crates (e.g. Jiff in addition to `chrono` and `time`)?\n\nThis has a lot of the same considerations as adding support for new databases (see above), but with one big additional problem: Semantic Versioning.\n\nWhen we add trait implementations for types from an external crate, that crate then becomes part of our public API. We become beholden to its release cycle.\n\nIf the crate's API is still evolving, meaning they are making breaking changes frequently, and thus releasing new major versions frequently, that then becomes a burden on us to upgrade and release a new major version as well so everyone _else_ can upgrade.\n\nWe don't have the maintainer bandwidth to support multiple major versions simultaneously (we have no Long-Term Support policy), so this means that users who want to keep up-to-date are forced to make frequent manual upgrades as well.\n\nThus, it is best that we stick to only supporting crates which have a stable API, and which are not making new major releases frequently.\n\nConversely, adding support for SQLx _in_ these crates may not be desirable either, since SQLx is a large dependency and a higher-level crate. In this case, the SemVer problem gets pushed onto the other crate.\n\nThere isn't a satisfying answer to this problem, but one option is to have an intermediate wrapper crate.\nFor example, [`jiff-sqlx`](https://crates.io/crates/jiff-sqlx), which is maintained by the author of Jiff.\nAPI changes to SQLx are pending to make this pattern easier to use.\n\n----------------------------------------------------------------\n### I'm getting `HandshakeFailure` or `CorruptMessage` when trying to connect to a server over TLS using RusTLS. What gives?\n\nTo encourage good security practices and limit cruft, RusTLS does not support older versions of TLS or cryptographic algorithms \nthat are considered insecure. `HandshakeFailure` is a normal error returned when RusTLS and the server cannot agree on parameters for\na secure connection. \n\nCheck the supported TLS versions for the database server version you're running. If it does not support TLS 1.2 or greater, then\nyou likely will not be able to connect to it with RusTLS.\n\nThe ideal solution, of course, is to upgrade your database server to a version that supports at least TLS 1.2.  \n\n* MySQL: [has supported TLS 1.2 since 5.6.46](https://dev.mysql.com/doc/refman/5.6/en/encrypted-connection-protocols-ciphers.html#encrypted-connection-supported-protocols). \n* PostgreSQL: depends on the system OpenSSL version.\n* MSSQL: TLS is not supported yet.\n\nIf you're running a third-party database that talks one of these protocols, consult its documentation for supported TLS versions.\n\nIf you're stuck on an outdated version, which is unfortunate but tends to happen for one reason or another, try switching to the corresponding\n`runtime-<tokio, async-std, actix>-native-tls` feature for SQLx. That will use the system APIs for TLS which tend to have much wider support.\nSee [the `native-tls` crate docs](https://docs.rs/native-tls/latest/native_tls/) for details.\n\nThe `CorruptMessage` error occurs in similar situations and many users have had success with switching to `-native-tls` to get around it.\nHowever, if you do encounter this error, please try to capture a Wireshark or `tcpdump` trace of the TLS handshake as the RusTLS folks are interested\nin covering cases that trigger this (as it might indicate a protocol handling bug or the server is doing something non-standard): \nhttps://github.com/rustls/rustls/issues/893\n\n----------------------------------------------------------------\n### How does SQLx help prevent SQL Injection?\n### How do Query Parameters work?\n### Why does SQLx use Prepared Statements for most queries?\n### Can I Use Query Parameters to add conditional SQL to my query?\n### Why can't I use DDL (e.g. `CREATE TABLE`, `ALTER TABLE`, etc.) with the `sqlx::query*()` functions or `sqlx::query*!()` macros?\n\nThese questions can all be answered by a thorough explanation of prepared statements. Feel free to skip the parts you already know.\n\nBack in the day, if a web application wanted to include user input in a SQL query,\na search parameter for example, it had no choice but to simply format that data into the query.\nPHP applications used to be full of snippets like this:\n\n```php\n/* Imagine this is user input */\n$city = \"Munich\";\n\n/* $query = \"SELECT country FROM city WHERE name='Munich'\" */\n$query = sprintf(\"SELECT country FROM city WHERE name='%s'\", $city);\n$result = $mysqli->query($query);\n```\n\nHowever, this leaves the application vulnerable to [SQL injection attacks](https://en.wikipedia.org/wiki/SQL_injection),\nbecause it's trivial to craft an input string that will terminate the existing query and begin a new one,\nand the database won't know the difference and will execute both. As illustrated in the famous XKCD #327:\n\n<a href=\"https://xkcd.com/327/\"><img src=\"https://imgs.xkcd.com/comics/exploits_of_a_mom.png\" title=\"Her daughter is named Help I'm trapped in a driver's license factory.\" alt=\"Exploits of a Mom\" srcset=\"https:////imgs.xkcd.com/comics/exploits_of_a_mom_2x.png 2x\" style=\"image-orientation:none\">\n\nThe fictional school's student database application might have contained a query that looked like this:\n```php\n$student_name = \"Robert');DROP TABLE Students;--\"\n\n$query = sprintf(\"INSERT INTO Students (name) VALUES ('%s')\", $student_name);\n$result = $mysqli->query($query);\n```\n\nWhen formatted into the middle of this query, the maliciously crafted input string closes the quotes and finishes the statement (`Robert');`),\nthen starts another one with the nefarious payload (`DROP TABLE Students;`), and causes the rest of the original query to be ignored by starting a SQL comment (`--`).\nThus, the database server sees, and executes, three separate statements like so:\n\n```SQL\nINSERT INTO Students(firstname) VALUES ('Robert');\nDROP TABLE Students;\n--');\n```\n\nAnd thus the school has lost this year's student records (at least they had last years' backed up?).\n\nThe original mitigation for this attack was to make sure that any untrustworthy user input was properly escaped (or \"sanitized\"),\nand many frameworks provided utility functions for this, such as PHP's [`mysqli::real_escape_string()`](https://www.php.net/manual/en/mysqli.real-escape-string.php) (not to be confused with the obsolete [`mysql_real_escape_string()`](https://www.php.net/manual/en/function.mysql-real-escape-string) or [`mysql_escape_string()`](https://www.php.net/manual/en/function.mysql-escape-string.php)).\n\nThese would prefix any syntactically significant characters (in this case, quotation marks) with a backslash,\nso it's less likely to affect the database server's interpretation of the query:\n\n```php\n$student_name = $mysqli->real_escape_string(\"Robert');DROP TABLE Students;--\");\n\n/*\n    Everything is okay now as the dastardly single-quote has been inactivated by the backslash:\n    \"INSERT INTO Students (name) VALUES ('Robert\\');DROP TABLE Students;--');\"\n*/\n$query = sprintf(\"INSERT INTO Students (name) VALUES ('%s')\", $student_name);\n```\n\nThe database server sees the backslash and knows that the single-quote is part of the string content, not its terminating character.\n\nHowever, this was something that you still had to _remember_ to do, making it only half a solution. Additionally, properly escaping the string requires knowledge of the current character set of the connection which is why the `mysqli` object is a required parameter \n(or the receiver in object-oriented style). And you could always just forget to wrap the string parameter in quotes (`'%s'`) in the first place, which these wouldn't help with.\n\nEven when everything is working correctly, formatting dynamic data into a query still requires the database server to \nre-parse and generate a new query plan with every new variant--caching helps, but is not a silver bullet.\n\n#### Prepared Statements to the rescue!\n\nThese solve both problems (injection and re-parsing) by **completely separating** the query from any dynamic input data.\n\nInstead of formatting data into the query, you use a (database-specific) token to signify a value that will be passed separately:\n\n```SQL\n-- MySQL\nINSERT INTO Students (name) VALUES(?);\n-- Postgres and SQLite\nINSERT INTO Students (name) VALUES($1);\n```\n\nThe database will substitute a given value when _executing_ the query, long after it's finished parsing it. \nThe database will effectively treat the parameter as a variable.\nThere is, by design, **no way** for a query parameter to modify the SQL of a query, \nunless you're using some `exec()`-like SQL function that lets you execute a string as a query, \nbut then hopefully you know what you're doing.\n\nIn fact, parsing and executing prepared statements are explicitly separate steps in pretty much every database's protocol,\nwhere the query string, without any values attached, is parsed first and given an identifier, then a separate execution step\nsimply passes that identifier along with the values to substitute.\n\nThe response from the initial parsing often contains useful metadata about the query, which SQLx's query macros use to great effect \n(see \"How do the query macros work under the hood?\" below).\n\nUnfortunately, query parameters do not appear to be standardized, as every database has a different syntax.\nLook through the project for specific examples for your database, and consult your database manual about prepared statements\nfor more information.\n\nThe syntax SQLite supports is effectively a superset of many databases' syntaxes, including MySQL and Postgres.\nTo simplify our examples, we use the same syntax for Postgres and SQLite; though SQLite's syntax technically allows\nalphanumeric identifiers, that's not currently exposed in SQLx, and it's expected to be a numeric 1-based index like Postgres.\n\nSome databases, like MySQL and PostgreSQL, may have special statements that let the user explicitly create and execute prepared statements (often `PREPARE` and `EXECUTE`, respectively),\nbut most of the time an application, or library like SQLx, will interact with prepared statements using specialized messages in the database's client/server protocol.\nPrepared statements created through this protocol may or may not be accessible using explicit SQL statements, depending on the database flavor.\n\nSince the dynamic data is handled separately, an application only needs to prepare a statement once,\nand then it can execute it as many times as it wants with all kinds of different data (at least of the same type and number).\nPrepared statements are generally tracked per-connection, so an application may need to re-prepare a statement several times over its lifetime as it opens new connections. \nIf it uses a connection pool, ideally all connections will eventually have all statements already prepared (assuming a closed set of statements),\nso the overhead of parsing and generating a query plan is amortized.\n\nQuery parameters are also usually transmitted in a compact binary format, which saves bandwidth over having to send them as human-readable strings.\n\nBecause of the obvious security and performance benefits of prepared statements, the design of SQLx tries to make them as easy to use and transparent as possible.\nThe `sqlx::query*()` family of functions, as well as the `sqlx::query*!()` macros, will always prefer prepared statements. This was an explicit goal from day one.\n\nSQLx will **never** substitute query parameters for values on the client-side, it will always let the database server handle that. We have concepts for making certain usage patterns easier, \nlike expanding a dynamic list of parameters (e.g. `?, ?, ?, ?, ...`) since MySQL and SQLite don't really support arrays, but will never simply format data into a query implicitly.\n\nOur pervasive use of prepared statements can cause some problems with third-party database implementations, e.g. projects like CockroachDB or PGBouncer that support the Postgres protocol but have their own semantics.\nIn this case, you might try setting [`.persistent(false)`](https://docs.rs/sqlx/latest/sqlx/query/struct.Query.html#method.persistent) before executing a query, which will cause the connection not to retain\nthe prepared statement after executing it.\n\nNot all SQL statements are allowed in prepared statements, either. \nAs a general rule, DML (Data Manipulation Language, i.e. `SELECT`, `INSERT`, `UPDATE`, `DELETE`) is allowed while DDL (Data Definition Language, e.g. `CREATE TABLE`, `ALTER TABLE`, etc.) is not.\nConsult your database manual for details.\n\nTo execute DDL requires using a different API than `query*()` or `query*!()` in SQLx. \nIdeally, we'd like to encourage you to use SQLx's built-in support for migrations (though that could be better documented, we'll get to it).\nHowever, in the event that isn't feasible, or you have different needs, you can execute pretty much any statement,\nincluding multiple statements separated by semicolons (`;`), by directly invoking methods of the [`Executor` trait](https://docs.rs/sqlx/latest/sqlx/trait.Executor.html#method.execute)\non any type that implements it, and passing your query string, e.g.:\n\n```rust\nuse sqlx::postgres::PgConnection;\nuse sqlx::Executor;\n\nlet mut conn: PgConnection = connect().await?;\n\nconn\n    .execute(\n        \"CREATE TABLE IF NOT EXISTS StudentContactInfo (student_id INTEGER, person_name TEXT, relation TEXT, phone TEXT);\\\n         INSERT INTO StudentContactInfo (student_id, person_name, relation, phone) \\\n             SELECT student_id, guardian_name, guardian_relation, guardian_phone FROM Students;\\\n         ALTER TABLE Students DROP guardian_name, guardian_relation, guardian_phone;\"\n    )\n    .await?;\n```\n\nThis is also pending a redesign to make it easier to discover and utilize.\n\n----------------------------------------------------------------\n### How can I do a `SELECT ... WHERE foo IN (...)` query?\n\n\nIn the future SQLx will support binding arrays as a comma-separated list for every database,\nbut unfortunately there's no general solution for that currently in SQLx itself.\nYou would need to manually generate the query, at which point it\ncannot be used with the macros.\n\nHowever, **in Postgres** you can work around this limitation by binding the arrays directly and using `= ANY()`:\n\n```rust\nlet db: PgPool = /* ... */;\nlet foo_ids: Vec<i64> = vec![/* ... */];\n\nlet foos = sqlx::query!(\n    \"SELECT * FROM foo WHERE id = ANY($1)\",\n    // a bug of the parameter typechecking code requires all array parameters to be slices\n    &foo_ids[..]\n)\n    .fetch_all(&db)\n    .await?;\n```\n\nEven when SQLx gains generic placeholder expansion for arrays, this will still be the optimal way to do it for Postgres,\nas comma-expansion means each possible length of the array generates a different query \n(and represents a combinatorial explosion if more than one array is used).\n\nNote that you can use any operator that returns a boolean, but beware that `!= ANY($1)` is **not equivalent** to `NOT IN (...)` as it effectively works like this:\n\n`lhs != ANY(rhs) -> false OR lhs != rhs[0] OR lhs != rhs[1] OR ... lhs != rhs[length(rhs) - 1]`\n\nThe equivalent of `NOT IN (...)` would be `!= ALL($1)`:\n\n`lhs != ALL(rhs) -> true AND lhs != rhs[0] AND lhs != rhs[1] AND ... lhs != rhs[length(rhs) - 1]`\n\nNote that `ANY` using any operator and passed an empty array will return `false`, thus the leading `false OR ...`.  \nMeanwhile, `ALL` with any operator and passed an empty array will return `true`, thus the leading `true AND ...`.\n\nSee also: [Postgres Manual, Section 9.24: Row and Array Comparisons](https://www.postgresql.org/docs/current/functions-comparisons.html)\n\n-----\n### How can I bind an array to a `VALUES()` clause? How can I do bulk inserts?\n\nLike the above, SQLx currently does not support this in the general case right now but will in the future.\n\nHowever, **Postgres** also has a feature to save the day here! You can pass an array to `UNNEST()` and\nit will treat it as a temporary table:\n\n```rust\nlet foo_texts: Vec<String> = vec![/* ... */];\n\nsqlx::query!(\n    // because `UNNEST()` is a generic function, Postgres needs the cast on the parameter here\n    // in order to know what type to expect there when preparing the query\n    \"INSERT INTO foo(text_column) SELECT * FROM UNNEST($1::text[])\",\n    &foo_texts[..]\n)\n    .execute(&db)\n    .await?; \n```\n\n`UNNEST()` can also take more than one array, in which case it'll treat each array as a column in the temporary table:\n\n```rust\n// this solution currently requires each column to be its own vector\n// in the future we're aiming to allow binding iterators directly as arrays\n// so you can take a vector of structs and bind iterators mapping to each field\nlet foo_texts: Vec<String> = vec![/* ... */];\nlet foo_bools: Vec<bool> = vec![/* ... */];\nlet foo_ints: Vec<i64> = vec![/* ... */];\nlet foo_opt_texts: Vec<Option<String>> = vec![/* ... */];\nlet foo_opt_naive_dts: Vec<Option<NaiveDateTime>> = vec![/* ... */]\n\n\nsqlx::query!(\n    \"\n        INSERT INTO foo(text_column, bool_column, int_column, opt_text_column, opt_naive_dt_column) \n        SELECT * FROM UNNEST($1::text[], $2::bool[], $3::int8[], $4::text[], $5::timestamp[])\n    \",\n    &foo_texts[..],\n    &foo_bools[..],\n    &foo_ints[..],\n    // Due to a limitation in how SQLx typechecks query parameters, `Vec<Option<T>>` is unable to be typechecked.\n    // This demonstrates the explicit type override syntax, which tells SQLx not to typecheck these parameters.\n    // See the documentation for `query!()` for more details.\n    &foo_opt_texts as &[Option<String>],\n    &foo_opt_naive_dts as &[Option<NaiveDateTime>]\n)\n    .execute(&db)\n    .await?;\n```\n\nAgain, even with comma-expanded lists in the future this will likely still be the most performant way to run bulk inserts\nwith Postgres--at least until we get around to implementing an interface for `COPY FROM STDIN`, though\nthis solution with `UNNEST()` will still be more flexible as you can use it in queries that are more complex\nthan just inserting into a table.\n\nNote that if some vectors are shorter than others, `UNNEST` will fill the corresponding columns with  `NULL`s\nto match the longest vector.\n\nFor example, if `foo_texts` is length 5, `foo_bools` is length 4, `foo_ints` is length 3, the resulting table will\nlook like this:\n\n| Row # | `text_column`  | `bool_column`  | `int_column`  |\n| ----- | -------------- | -------------- | ------------- |\n| 1     | `foo_texts[0]` | `foo_bools[0]` | `foo_ints[0]` |\n| 2     | `foo_texts[1]` | `foo_bools[1]` | `foo_ints[1]` |\n| 3     | `foo_texts[2]` | `foo_bools[2]` | `foo_ints[2]` |\n| 4     | `foo_texts[3]` | `foo_bools[3]` | `NULL`        |\n| 5     | `foo_texts[4]` | `NULL`         | `NULL`        |\n\nSee Also:\n* [Postgres Manual, Section 7.2.1.4: Table Functions](https://www.postgresql.org/docs/current/queries-table-expressions.html#QUERIES-TABLEFUNCTIONS)\n* [Postgres Manual, Section 9.19: Array Functions and Operators](https://www.postgresql.org/docs/current/functions-array.html)\n\n----\n### How do I compile with the macros without needing a database, e.g. in CI?\n\nThe macros support an offline mode which saves data for existing queries to a `.sqlx` directory,\nso the macros can just read those instead of talking to a database.\n\nSee the following:\n\n* [the docs for `query!()`](https://docs.rs/sqlx/0.5.5/sqlx/macro.query.html#offline-mode-requires-the-offline-feature)\n* [the README for `sqlx-cli`](sqlx-cli/README.md#enable-building-in-offline-mode-with-query)\n\nTo keep `.sqlx` up-to-date you need to run `cargo sqlx prepare` before every commit that\nadds or changes a query; you can do this with a Git pre-commit hook:\n\n```shell\n$ echo \"cargo sqlx prepare > /dev/null 2>&1; git add .sqlx > /dev/null\" > .git/hooks/pre-commit \n```\n\nNote that this may make committing take some time as it'll cause your project to be recompiled, and\nas an ergonomic choice it does _not_ block committing if `cargo sqlx prepare` fails.\n\nWe're working on a way for the macros to save their data to the filesystem automatically which should be part of SQLx 0.7,\nso your pre-commit hook would then just need to stage the changed files. This can be enabled by creating a directory \nand setting the `SQLX_OFFLINE_DIR` environment variable to it before compiling. \nHowever, this behaviour is not considered stable and it is still recommended to use `cargo sqlx prepare`.\n\n----\n\n### How do the query macros work under the hood?\n\nThe macros work by talking to the database at compile time. When a(n) SQL client asks to create a prepared statement \nfrom a query string, the response from the server typically includes information about the following:\n\n* the number of bind parameters, and their expected types if the database is capable of inferring that\n* the number, names and types of result columns, as well as the original table and columns names before aliasing \n  \nIn MySQL/MariaDB, we also get boolean flag signaling if a column is `NOT NULL`, however \nin Postgres and SQLite, we need to do a bit more work to determine whether a column can be `NULL` or not.\n\nAfter preparing, the Postgres driver will first look up the result columns in their source table and check if they have \na `NOT NULL` constraint. Then, it will execute `EXPLAIN (VERBOSE, FORMAT JSON) <your query>` to determine which columns \ncome from half-open joins (LEFT and RIGHT joins), which makes a normally `NOT NULL` column nullable. Since the\n`EXPLAIN VERBOSE` format is not stable or completely documented, this inference isn't perfect. However, it does err on\nthe side of producing false-positives (marking a column nullable when it's `NOT NULL`) to avoid errors at runtime.\n\nIf you do encounter false-positives please feel free to open an issue; make sure to include your query, any relevant\nschema as well as the output of `EXPLAIN (VERBOSE, FORMAT JSON) <your query>` which will make this easier to debug.\n\nThe SQLite driver will pull the bytecode of the prepared statement and step through it to find any instructions\nthat produce a null value for any column in the output.\n\n---\n### Why can't SQLx just look at my database schema/migrations and parse the SQL itself?\n\nTake a moment and think of the effort that would be required to do that.\n\nTo implement this for a single database driver, SQLx would need to:\n\n* know how to parse SQL, and not just standard SQL but the specific dialect of that particular database\n* know how to analyze and typecheck SQL queries in the context of the original schema\n* if inferring schema from migrations it would need to simulate all the schema-changing effects of those migrations\n\nThis is effectively reimplementing a good chunk of the database server's frontend, \n\n_and_ maintaining and ensuring correctness of that reimplementation,\n\nincluding bugs and idiosyncrasies,\n\nfor the foreseeable future,\n\nfor _every_ database we intend to support. \n\nEven Sisyphus would pity us.\n\n----\n\n### Why does my project using sqlx query macros not build on docs.rs?\n\nDocs.rs doesn't have access to your database, so it needs to be provided prepared queries in a `.sqlx` directory and be instructed to set the `SQLX_OFFLINE` environment variable to true while compiling your project. Luckily for us, docs.rs creates a `DOCS_RS` environment variable that we can access in a custom build script to achieve this functionality.\n\nTo do so, first, make sure that you have run `cargo sqlx prepare` to generate a `.sqlx` directory in your project.\n\nNext, create a file called `build.rs` in the root of your project directory (at the same level as `Cargo.toml`). Add the following code to it:\n```rs\nfn main() {\n    // When building in docs.rs, we want to set SQLX_OFFLINE mode to true\n    if std::env::var_os(\"DOCS_RS\").is_some() {\n        println!(\"cargo:rustc-env=SQLX_OFFLINE=true\");\n    }\n}\n```\n"
  },
  {
    "path": "LICENSE-APACHE",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction,\nand distribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by\nthe copyright owner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all\nother entities that control, are controlled by, or are under common\ncontrol with that entity. For the purposes of this definition,\n\"control\" means (i) the power, direct or indirect, to cause the\ndirection or management of such entity, whether by contract or\notherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity\nexercising permissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications,\nincluding but not limited to software source code, documentation\nsource, and configuration files.\n\n\"Object\" form shall mean any form resulting from mechanical\ntransformation or translation of a Source form, including but\nnot limited to compiled object code, generated documentation,\nand conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or\nObject form, made available under the License, as indicated by a\ncopyright 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\nform, that is based on (or derived from) the Work and for which the\neditorial revisions, annotations, elaborations, or other modifications\nrepresent, as a whole, an original work of authorship. For the purposes\nof this License, Derivative Works shall not include works that remain\nseparable from, or merely link (or bind by name) to the interfaces of,\nthe Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including\nthe original version of the Work and any modifications or additions\nto that Work or Derivative Works thereof, that is intentionally\nsubmitted to Licensor for inclusion in the Work by the copyright owner\nor by an individual or Legal Entity authorized to submit on behalf of\nthe copyright owner. For the purposes of this definition, \"submitted\"\nmeans any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems,\nand issue tracking systems that are managed by, or on behalf of, the\nLicensor for the purpose of discussing and improving the Work, but\nexcluding communication that is conspicuously marked or otherwise\ndesignated in writing by the copyright owner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity\non behalf of whom a Contribution has been received by Licensor and\nsubsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of\nthis License, each Contributor hereby grants to You a perpetual,\nworldwide, non-exclusive, no-charge, royalty-free, irrevocable\ncopyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the\nWork and such Derivative Works in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of\nthis License, each Contributor hereby grants to You a perpetual,\nworldwide, non-exclusive, no-charge, royalty-free, irrevocable\n(except as stated in this section) patent license to make, have made,\nuse, offer to sell, sell, import, and otherwise transfer the Work,\nwhere such license applies only to those patent claims licensable\nby such Contributor that are necessarily infringed by their\nContribution(s) alone or by combination of their Contribution(s)\nwith the Work to which such Contribution(s) was submitted. If You\ninstitute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work\nor a Contribution incorporated within the Work constitutes direct\nor contributory patent infringement, then any patent licenses\ngranted to You under this License for that Work shall terminate\nas of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the\nWork or Derivative Works thereof in any medium, with or without\nmodifications, and in Source or Object form, provided that You\nmeet the following conditions:\n\n(a) You must give any other recipients of the Work or\nDerivative Works a copy of this License; and\n\n(b) You must cause any modified files to carry prominent notices\nstating that You changed the files; and\n\n(c) You must retain, in the Source form of any Derivative Works\nthat You distribute, all copyright, patent, trademark, and\nattribution notices from the Source form of the Work,\nexcluding those notices that do not pertain to any part of\nthe Derivative Works; and\n\n(d) If the Work includes a \"NOTICE\" text file as part of its\ndistribution, then any Derivative Works that You distribute must\ninclude a readable copy of the attribution notices contained\nwithin such NOTICE file, excluding those notices that do not\npertain to any part of the Derivative Works, in at least one\nof the following places: within a NOTICE text file distributed\nas part of the Derivative Works; within the Source form or\ndocumentation, if provided along with the Derivative Works; or,\nwithin a display generated by the Derivative Works, if and\nwherever such third-party notices normally appear. The contents\nof the NOTICE file are for informational purposes only and\ndo not modify the License. You may add Your own attribution\nnotices within Derivative Works that You distribute, alongside\nor as an addendum to the NOTICE text from the Work, provided\nthat such additional attribution notices cannot be construed\nas modifying the License.\n\nYou may add Your own copyright statement to Your modifications and\nmay provide additional or different license terms and conditions\nfor use, reproduction, or distribution of Your modifications, or\nfor any such Derivative Works as a whole, provided Your use,\nreproduction, and distribution of the Work otherwise complies with\nthe conditions stated in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise,\nany Contribution intentionally submitted for inclusion in the Work\nby You to the Licensor shall be under the terms and conditions of\nthis License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify\nthe terms of any separate license agreement you may have executed\nwith Licensor regarding such Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\nnames, trademarks, service marks, or product names of the Licensor,\nexcept as required for reasonable and customary use in describing the\norigin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or\nagreed to in writing, Licensor provides the Work (and each\nContributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\nimplied, including, without limitation, any warranties or conditions\nof TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\nPARTICULAR PURPOSE. You are solely responsible for determining the\nappropriateness of using or redistributing the Work and assume any\nrisks associated with Your exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory,\nwhether in tort (including negligence), contract, or otherwise,\nunless required by applicable law (such as deliberate and grossly\nnegligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special,\nincidental, or consequential damages of any character arising as a\nresult of this License or out of the use or inability to use the\nWork (including but not limited to damages for loss of goodwill,\nwork stoppage, computer failure or malfunction, or any and all\nother commercial damages or losses), even if such Contributor\nhas been advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing\nthe Work or Derivative Works thereof, You may choose to offer,\nand charge a fee for, acceptance of support, warranty, indemnity,\nor other liability obligations and/or rights consistent with this\nLicense. However, in accepting such obligations, You may act only\non Your own behalf and on Your sole responsibility, not on behalf\nof any other Contributor, and only if You agree to indemnify,\ndefend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason\nof your accepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work.\n\nTo apply the Apache License to your work, attach the following\nboilerplate notice, with the fields enclosed by brackets \"[]\"\nreplaced with your own identifying information. (Don't include\nthe brackets!)  The text should be enclosed in the appropriate\ncomment syntax for the file format. We also recommend that a\nfile or class name and description of purpose be included on the\nsame \"printed page\" as the copyright notice for easier\nidentification within third-party archives.\n\nCopyright 2020 LaunchBadge, LLC\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License."
  },
  {
    "path": "LICENSE-MIT",
    "content": "Copyright (c) 2020 LaunchBadge, LLC\n\nPermission is hereby granted, free of charge, to any\nperson obtaining a copy of this software and associated\ndocumentation files (the \"Software\"), to deal in the\nSoftware without restriction, including without\nlimitation the rights to use, copy, modify, merge,\npublish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software\nis furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice\nshall be included in all copies or substantial portions\nof the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF\nANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED\nTO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A\nPARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT\nSHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR\nIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h1 align=\"center\">SQLx</h1>\n<div align=\"center\">\n <strong>\n   🧰 The Rust SQL Toolkit\n </strong>\n</div>\n\n<br />\n\n<div align=\"center\">\n  <!-- Github Actions -->\n  <a href=\"https://github.com/launchbadge/sqlx/actions/workflows/sqlx.yml?query=branch%3Amain\">\n    <img src=\"https://img.shields.io/github/actions/workflow/status/launchbadge/sqlx/sqlx.yml?branch=main&style=flat-square\" alt=\"actions status\" /></a>\n  <!-- Version -->\n  <a href=\"https://crates.io/crates/sqlx\">\n    <img src=\"https://img.shields.io/crates/v/sqlx.svg?style=flat-square\"\n    alt=\"Crates.io version\" /></a>\n  <!-- Discord -->\n  <a href=\"https://discord.gg/uuruzJ7\">\n  <img src=\"https://img.shields.io/discord/665528275556106240?style=flat-square\" alt=\"chat\" /></a>\n  <!-- Docs -->\n  <a href=\"https://docs.rs/sqlx\">\n  <img src=\"https://img.shields.io/badge/docs-latest-blue.svg?style=flat-square\" alt=\"docs.rs docs\" /></a>\n  <!-- Downloads -->\n  <a href=\"https://crates.io/crates/sqlx\">\n    <img src=\"https://img.shields.io/crates/d/sqlx.svg?style=flat-square\" alt=\"Download\" />\n  </a>\n</div>\n\n<div align=\"center\">\n  <h4>\n    <a href=\"#install\">\n      Install\n    </a>\n    <span> | </span>\n    <a href=\"#usage\">\n      Usage\n    </a>\n    <span> | </span>\n    <a href=\"https://docs.rs/sqlx\">\n      Docs\n    </a>\n    <span> | </span>\n    <a href=\"https://github.com/launchbadge/sqlx/wiki/Ecosystem\">\n      Ecosystem\n    </a>    \n    <span> | </span>\n    <a href=\"https://discord.gg/uuruzJ7\">\n      Discord\n    </a>\n  </h4>\n</div>\n\n<br />\n\n<div align=\"center\">\n  <small>Built with ❤️ by <a href=\"https://launchbadge.com\">The LaunchBadge team</a></small>\n</div>\n\n<br />\n\n<div align=\"center\">\n    <h5>Have a question? Be sure to <a href=\"FAQ.md\">check the FAQ first!</a></h5>\n</div>\n\n<br />\n\nSQLx is an async, pure Rust<sub>†</sub> SQL crate featuring compile-time checked queries without a DSL.\n\n-   **Truly Asynchronous**. Built from the ground-up using async/await for maximum concurrency.\n\n-   **Compile-time checked queries** (if you want). See [SQLx is not an ORM](#sqlx-is-not-an-orm).\n\n-   **Database Agnostic**. Support for [PostgreSQL], [MySQL], [MariaDB], [SQLite].\n    -   [MSSQL] was supported prior to version 0.7, but has been removed pending a full rewrite of the driver as part of our [SQLx Pro initiative].\n\n-   **Pure Rust**. The Postgres and MySQL/MariaDB drivers are written in pure Rust using **zero** unsafe<sub>††</sub> code.\n\n-   **Runtime Agnostic**. Works on different runtimes ([`async-std`] / [`tokio`] / [`actix`]) and TLS backends ([`native-tls`], [`rustls`]).\n\n<small><small>\n\n† The SQLite driver uses the libsqlite3 C library as SQLite is an embedded database (the only way\nwe could be pure Rust for SQLite is by porting _all_ of SQLite to Rust).\n\n†† SQLx uses `#![forbid(unsafe_code)]` unless the `sqlite` feature is enabled.\nThe SQLite driver directly invokes the SQLite3 API via `libsqlite3-sys`, which requires `unsafe`.\n\n</small></small>\n\n[postgresql]: http://postgresql.org/\n[sqlite]: https://sqlite.org/\n[mysql]: https://www.mysql.com/\n[mariadb]: https://www.mariadb.org/\n[mssql]: https://www.microsoft.com/en-us/sql-server\n[SQLx Pro initiative]: https://github.com/launchbadge/sqlx/discussions/1616\n\n---\n\n-   Cross-platform. Being native Rust, SQLx will compile anywhere Rust is supported.\n\n-   Built-in connection pooling with `sqlx::Pool`.\n\n-   Row streaming. Data is read asynchronously from the database and decoded on demand.\n\n-   Automatic statement preparation and caching. When using the high-level query API (`sqlx::query`), statements are\n    prepared and cached per connection.\n\n-   Simple (unprepared) query execution including fetching results into the same `Row` types used by\n    the high-level API. Supports batch execution and returns results from all statements.\n\n-   Transport Layer Security (TLS) where supported ([MySQL], [MariaDB] and [PostgreSQL]).\n\n-   Asynchronous notifications using `LISTEN` and `NOTIFY` for [PostgreSQL].\n\n-   Nested transactions with support for save points.\n\n-   `Any` database driver for changing the database driver at runtime. An `AnyPool` connects to the driver indicated by the URL scheme.\n\n## Install\n\nSQLx is compatible with the [`async-std`], [`tokio`], and [`actix`] runtimes; and, the [`native-tls`] and [`rustls`] TLS backends. When adding the dependency, you must choose a runtime feature that is `runtime` + `tls`.\n\n[`async-std`]: https://github.com/async-rs/async-std\n[`tokio`]: https://github.com/tokio-rs/tokio\n[`actix`]: https://github.com/actix/actix-net\n[`native-tls`]: https://crates.io/crates/native-tls\n[`rustls`]: https://crates.io/crates/rustls\n\n```toml\n# Cargo.toml\n[dependencies]\n# PICK ONE OF THE FOLLOWING:\n\n# tokio (no TLS)\nsqlx = { version = \"0.8\", features = [ \"runtime-tokio\" ] }\n# tokio + native-tls\nsqlx = { version = \"0.8\", features = [ \"runtime-tokio\", \"tls-native-tls\" ] }\n# tokio + rustls with ring and WebPKI CA certificates\nsqlx = { version = \"0.8\", features = [ \"runtime-tokio\", \"tls-rustls-ring-webpki\" ] }\n# tokio + rustls with ring and platform's native CA certificates\nsqlx = { version = \"0.8\", features = [ \"runtime-tokio\", \"tls-rustls-ring-native-roots\" ] }\n# tokio + rustls with aws-lc-rs\nsqlx = { version = \"0.8\", features = [ \"runtime-tokio\", \"tls-rustls-aws-lc-rs\" ] }\n\n# async-std (no TLS)\nsqlx = { version = \"0.8\", features = [ \"runtime-async-std\" ] }\n# async-std + native-tls\nsqlx = { version = \"0.8\", features = [ \"runtime-async-std\", \"tls-native-tls\" ] }\n# async-std + rustls with ring and WebPKI CA certificates\nsqlx = { version = \"0.8\", features = [ \"runtime-async-std\", \"tls-rustls-ring-webpki\" ] }\n# async-std + rustls with ring and platform's native CA certificates\nsqlx = { version = \"0.8\", features = [ \"runtime-async-std\", \"tls-rustls-ring-native-roots\" ] }\n# async-std + rustls with aws-lc-rs\nsqlx = { version = \"0.8\", features = [ \"runtime-async-std\", \"tls-rustls-aws-lc-rs\" ] }\n```\n\n#### Cargo Feature Flags\n\nFor backward-compatibility reasons, the runtime and TLS features can either be chosen together as a single feature,\nor separately.\n\nFor forward compatibility, you should use the separate runtime and TLS features as the combination features may\nbe removed in the future.\n\n-   `runtime-async-std`: Use the `async-std` runtime without enabling a TLS backend.\n\n-   `runtime-tokio`: Use the `tokio` runtime without enabling a TLS backend.\n\n    - Actix-web is fully compatible with Tokio and so a separate runtime feature is no longer needed.\n\n-   `tls-native-tls`: Use the `native-tls` TLS backend (OpenSSL on *nix, SChannel on Windows, Secure Transport on macOS).\n\n-   `tls-rustls`: Use the `rustls` TLS backend (cross-platform backend, only supports TLS 1.2 and 1.3).\n\n-   `postgres`: Add support for the Postgres database server.\n\n-   `mysql`: Add support for the MySQL/MariaDB database server.\n\n-   `mssql`: Add support for the MSSQL database server.\n\n-   `sqlite`: Add support for the self-contained [SQLite](https://sqlite.org/) database engine with SQLite bundled and statically-linked.\n\n-   `sqlite-unbundled`: The same as above (`sqlite`), but link SQLite from the system instead of the bundled version.\n    * Allows updating SQLite independently of SQLx or using forked versions.\n    * You must have SQLite installed on the system or provide a path to the library at build time.\n       See [the `rusqlite` README](https://github.com/rusqlite/rusqlite?tab=readme-ov-file#notes-on-building-rusqlite-and-libsqlite3-sys) for details.\n    * May result in link errors if the SQLite version is too old. Version `3.20.0` or newer is recommended.\n    * Can increase build time due to the use of bindgen.\n\n-   `sqlite-preupdate-hook`: enables SQLite's [preupdate hook](https://sqlite.org/c3ref/preupdate_count.html) API.\n    * Exposed as a separate feature because it's generally not enabled by default.\n    * Using this feature with `sqlite-unbundled` may cause linker failures if the system SQLite version does not support it.\n\n-   `any`: Add support for the `Any` database driver, which can proxy to a database driver at runtime.\n\n-   `derive`: Add support for the derive family macros, those are `FromRow`, `Type`, `Encode`, `Decode`.\n\n-   `macros`: Add support for the `query*!` macros, which allows compile-time checked queries.\n\n-   `migrate`: Add support for the migration management and `migrate!` macro, which allow compile-time embedded migrations.\n\n-   `uuid`: Add support for UUID.\n\n-   `chrono`: Add support for date and time types from `chrono`.\n\n-   `time`: Add support for date and time types from `time` crate (alternative to `chrono`, which is preferred by `query!` macro, if both enabled)\n\n-   `bstr`: Add support for `bstr::BString`.\n\n-   `bigdecimal`: Add support for `NUMERIC` using the `bigdecimal` crate.\n\n-   `rust_decimal`: Add support for `NUMERIC` using the `rust_decimal` crate.\n\n-   `ipnet`: Add support for `INET` and `CIDR` (in postgres) using the `ipnet` crate.\n\n-   `ipnetwork`: Add support for `INET` and `CIDR` (in postgres) using the `ipnetwork` crate.\n\n-   `json`: Add support for `JSON` and `JSONB` (in postgres) using the `serde_json` crate.\n\n-   Offline mode is now always enabled. See [sqlx-cli/README.md][readme-offline].\n\n[readme-offline]: sqlx-cli/README.md#enable-building-in-offline-mode-with-query\n\n## SQLx is not an ORM!\n\nSQLx supports **compile-time checked queries**. It does not, however, do this by providing a Rust\nAPI or DSL (domain-specific language) for building queries. Instead, it provides macros that take\nregular SQL as input and ensure that it is valid for your database. The way this works is that\nSQLx connects to your development DB at compile time to have the database itself verify (and return\nsome info on) your SQL queries. This has some potentially surprising implications:\n\n- Since SQLx never has to parse the SQL string itself, any syntax that the development DB accepts\n  can be used (including things added by database extensions)\n- Due to the different amount of information databases let you retrieve about queries, the extent of\n  SQL verification you get from the query macros depends on the database\n\n**If you are looking for an (asynchronous) ORM,** you can check out our new [Ecosystem wiki page](https://github.com/launchbadge/sqlx/wiki/Ecosystem#orms)!\n\n[`ormx`]: https://crates.io/crates/ormx\n[`SeaORM`]: https://github.com/SeaQL/sea-orm\n## Usage\n\nSee the `examples/` folder for more in-depth usage.\n\n### Quickstart\n\n```rust\nuse sqlx::postgres::PgPoolOptions;\n// use sqlx::mysql::MySqlPoolOptions;\n// etc.\n\n#[async_std::main] // Requires the `attributes` feature of `async-std`\n// or #[tokio::main]\n// or #[actix_web::main]\nasync fn main() -> Result<(), sqlx::Error> {\n    // Create a connection pool\n    //  for MySQL/MariaDB, use MySqlPoolOptions::new()\n    //  for SQLite, use SqlitePoolOptions::new()\n    //  etc.\n    let pool = PgPoolOptions::new()\n        .max_connections(5)\n        .connect(\"postgres://postgres:password@localhost/test\").await?;\n\n    // Make a simple query to return the given parameter (use a question mark `?` instead of `$1` for MySQL/MariaDB)\n    let row: (i64,) = sqlx::query_as(\"SELECT $1\")\n        .bind(150_i64)\n        .fetch_one(&pool).await?;\n\n    assert_eq!(row.0, 150);\n\n    Ok(())\n}\n```\n\n\n### Connecting\n\nA single connection can be established using any of the database connection types and calling `connect()`.\n\n```rust\nuse sqlx::Connection;\n\nlet conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n```\n\nGenerally, you will want to instead create a connection pool (`sqlx::Pool`) for the application to\nregulate how many server-side connections it's using.\n\n```rust\nlet pool = MySqlPool::connect(\"mysql://user:pass@host/database\").await?;\n```\n\n### Querying\n\nIn SQL, queries can be separated into prepared (parameterized) or unprepared (simple). Prepared queries have their\nquery plan _cached_, use a binary mode of communication (lower bandwidth and faster decoding), and utilize parameters\nto avoid SQL injection. Unprepared queries are simple and intended only for use where a prepared statement\nwill not work, such as various database commands (e.g., `PRAGMA` or `SET` or `BEGIN`).\n\nSQLx supports all operations with both types of queries. In SQLx, a `&str` is treated as an unprepared query,\nand a `Query` or `QueryAs` struct is treated as a prepared query.\n\n```rust\n// low-level, Executor trait\nconn.execute(\"BEGIN\").await?; // unprepared, simple query\nconn.execute(sqlx::query(\"DELETE FROM table\")).await?; // prepared, cached query\n```\n\nWe should prefer to use the high-level `query` interface whenever possible. To make this easier, there are finalizers\non the type to avoid the need to wrap with an executor.\n\n```rust\nsqlx::query(\"DELETE FROM table\").execute(&mut conn).await?;\nsqlx::query(\"DELETE FROM table\").execute(&pool).await?;\n```\n\nThe `execute` query finalizer returns the number of affected rows, if any, and drops all received results.\nIn addition, there are `fetch`, `fetch_one`, `fetch_optional`, and `fetch_all` to receive results.\n\nThe `Query` type returned from `sqlx::query` will return `Row<'conn>` from the database. Column values can be accessed\nby ordinal or by name with `row.get()`. As the `Row` retains an immutable borrow on the connection, only one\n`Row` may exist at a time.\n\nThe `fetch` query finalizer returns a stream-like type that iterates through the rows in the result sets.\n\n```rust\n// provides `try_next`\nuse futures_util::TryStreamExt;\n// provides `try_get`\nuse sqlx::Row;\n\nlet mut rows = sqlx::query(\"SELECT * FROM users WHERE email = ?\")\n    .bind(email)\n    .fetch(&mut conn);\n\nwhile let Some(row) = rows.try_next().await? {\n    // map the row into a user-defined domain type\n    let email: &str = row.try_get(\"email\")?;\n}\n```\n\nTo assist with mapping the row into a domain type, one of two idioms may be used:\n\n```rust\nlet mut stream = sqlx::query(\"SELECT * FROM users\")\n    .map(|row: PgRow| {\n        // map the row into a user-defined domain type\n    })\n    .fetch(&mut conn);\n```\n\n```rust\n#[derive(sqlx::FromRow)]\nstruct User { name: String, id: i64 }\n\nlet mut stream = sqlx::query_as::<_, User>(\"SELECT * FROM users WHERE email = ? OR name = ?\")\n    .bind(user_email)\n    .bind(user_name)\n    .fetch(&mut conn);\n```\n\nInstead of a stream of results, we can use `fetch_one` or `fetch_optional` to request one required or optional result\nfrom the database.\n\n### Compile-time verification\n\nWe can use the macro, `sqlx::query!` to achieve compile-time syntactic and semantic verification of the SQL, with\nan output to an anonymous record type where each SQL column is a Rust field (using raw identifiers where needed).\n\n```rust\nlet countries = sqlx::query!(\n        \"\nSELECT country, COUNT(*) as count\nFROM users\nGROUP BY country\nWHERE organization = ?\n        \",\n        organization\n    )\n    .fetch_all(&pool) // -> Vec<{ country: String, count: i64 }>\n    .await?;\n\n// countries[0].country\n// countries[0].count\n```\n\nDifferences from `query()`:\n\n-   The input (or bind) parameters must be given all at once (and they are compile-time validated to be\n    the right number and the right type).\n\n-   The output type is an anonymous record. In the above example the type would be similar to:\n\n    ```rust\n    { country: String, count: i64 }\n    ```\n\n-   The `DATABASE_URL` environment variable must be set at build time to a database which it can prepare\n    queries against; the database does not have to contain any data but must be the same\n    kind (MySQL, Postgres, etc.) and have the same schema as the database you will be connecting to at runtime.\n\n    For convenience, you can use [a `.env` file][dotenv]<sup>1</sup> to set DATABASE_URL so that you don't have to pass it every time:\n\n    ```\n    DATABASE_URL=mysql://localhost/my_database\n    ```\n\n[dotenv]: https://github.com/dotenv-rs/dotenv#examples\n\nThe biggest downside to `query!()` is that the output type cannot be named (due to Rust not\nofficially supporting anonymous records). To address that, there is a `query_as!()` macro that is\nmostly identical except that you can name the output type.\n\n```rust\n// no traits are needed\nstruct Country { country: String, count: i64 }\n\nlet countries = sqlx::query_as!(Country,\n        \"\nSELECT country, COUNT(*) as count\nFROM users\nGROUP BY country\nWHERE organization = ?\n        \",\n        organization\n    )\n    .fetch_all(&pool) // -> Vec<Country>\n    .await?;\n\n// countries[0].country\n// countries[0].count\n```\n\nTo avoid the need of having a development database around to compile the project even when no\nmodifications (to the database-accessing parts of the code) are done, you can enable \"offline mode\"\nto cache the results of the SQL query analysis using the `sqlx` command-line tool. See\n[sqlx-cli/README.md](./sqlx-cli/README.md#enable-building-in-offline-mode-with-query).\n\nCompile-time verified queries do quite a bit of work at compile time. Incremental actions like\n`cargo check` and `cargo build` can be significantly faster when using an optimized build by\nputting the following in your `Cargo.toml` (More information in the\n[Profiles section](https://doc.rust-lang.org/cargo/reference/profiles.html) of The Cargo Book)\n\n```toml\n[profile.dev.package.sqlx-macros]\nopt-level = 3\n```\n\n<sup>1</sup> The `dotenv` crate itself appears abandoned as of [December 2021](https://github.com/dotenv-rs/dotenv/issues/74)\nso we now use the `dotenvy` crate instead. The file format is the same.\n\n## Safety\n\nThis crate uses `#![forbid(unsafe_code)]` to ensure everything is implemented in 100% Safe Rust.\n\nIf the `sqlite` feature is enabled, this is downgraded to `#![deny(unsafe_code)]` with `#![allow(unsafe_code)]` on the\n`sqlx::sqlite` module. There are several places where we interact with the C SQLite API. We try to document each call for the invariants we're assuming. We absolutely welcome auditing of, and feedback on, our unsafe code usage.\n\n## License\n\nLicensed under either of\n\n-   Apache License, Version 2.0\n    ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n-   MIT license\n    ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\n## Contribution\n\nUnless you explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be\ndual licensed as above, without any additional terms or conditions.\n"
  },
  {
    "path": "benches/sqlite/describe.rs",
    "content": "use criterion::BenchmarkId;\nuse criterion::Criterion;\nuse criterion::{criterion_group, criterion_main};\n\nuse sqlx::sqlite::{Sqlite, SqliteConnection};\nuse sqlx::Executor;\nuse sqlx_test::new;\n\n// Here we have an async function to benchmark\nasync fn do_describe_trivial(db: &std::cell::RefCell<SqliteConnection>) {\n    db.borrow_mut().describe(\"select 1\").await.unwrap();\n}\n\nasync fn do_describe_recursive(db: &std::cell::RefCell<SqliteConnection>) {\n    db.borrow_mut()\n        .describe(\n            r#\"\n            WITH RECURSIVE schedule(begin_date) AS MATERIALIZED (\n                SELECT datetime('2022-10-01')\n                WHERE datetime('2022-10-01') < datetime('2022-11-03')\n                UNION ALL\n                SELECT datetime(begin_date,'+1 day')\n                FROM schedule\n                WHERE datetime(begin_date) < datetime(?2)\n            )\n            SELECT\n            begin_date\n            FROM schedule\n            GROUP BY begin_date\n            \"#,\n        )\n        .await\n        .unwrap();\n}\n\nasync fn do_describe_insert(db: &std::cell::RefCell<SqliteConnection>) {\n    db.borrow_mut()\n        .describe(\"INSERT INTO tweet (id, text) VALUES (2, 'Hello') RETURNING *\")\n        .await\n        .unwrap();\n}\n\nasync fn do_describe_insert_fks(db: &std::cell::RefCell<SqliteConnection>) {\n    db.borrow_mut()\n        .describe(\"insert into statements (text) values ('a') returning id\")\n        .await\n        .unwrap();\n}\n\nasync fn init_connection() -> SqliteConnection {\n    let mut conn = new::<Sqlite>().await.unwrap();\n\n    conn.execute(\n        r#\"\n        CREATE TEMPORARY TABLE statements (\n          id integer not null primary key,\n          text text not null\n        );\n\n        CREATE TEMPORARY TABLE votes1 (statement_id integer not null references statements(id));\n        CREATE TEMPORARY TABLE votes2 (statement_id integer not null references statements(id));\n        CREATE TEMPORARY TABLE votes3 (statement_id integer not null references statements(id));\n        CREATE TEMPORARY TABLE votes4 (statement_id integer not null references statements(id));\n        CREATE TEMPORARY TABLE votes5 (statement_id integer not null references statements(id));\n        CREATE TEMPORARY TABLE votes6 (statement_id integer not null references statements(id));\n        --CREATE TEMPORARY TABLE votes7 (statement_id integer not null references statements(id));\n        --CREATE TEMPORARY TABLE votes8 (statement_id integer not null references statements(id));\n        --CREATE TEMPORARY TABLE votes9 (statement_id integer not null references statements(id));\n        --CREATE TEMPORARY TABLE votes10 (statement_id integer not null references statements(id));\n        --CREATE TEMPORARY TABLE votes11 (statement_id integer not null references statements(id));\n    \"#,\n    )\n    .await\n    .unwrap();\n    conn\n}\n\nfn describe_trivial(c: &mut Criterion) {\n    let runtime = tokio::runtime::Runtime::new().unwrap();\n    let db = std::cell::RefCell::new(runtime.block_on(init_connection()));\n\n    c.bench_with_input(\n        BenchmarkId::new(\"select\", \"trivial\"),\n        &db,\n        move |b, db_ref| {\n            // Insert a call to `to_async` to convert the bencher to async mode.\n            // The timing loops are the same as with the normal bencher.\n            b.to_async(&runtime).iter(|| do_describe_trivial(db_ref));\n        },\n    );\n}\n\nfn describe_recursive(c: &mut Criterion) {\n    let runtime = tokio::runtime::Runtime::new().unwrap();\n    let db = std::cell::RefCell::new(runtime.block_on(init_connection()));\n\n    c.bench_with_input(\n        BenchmarkId::new(\"select\", \"recursive\"),\n        &db,\n        move |b, db_ref| {\n            // Insert a call to `to_async` to convert the bencher to async mode.\n            // The timing loops are the same as with the normal bencher.\n            b.to_async(&runtime).iter(|| do_describe_recursive(db_ref));\n        },\n    );\n}\n\nfn describe_insert(c: &mut Criterion) {\n    let runtime = tokio::runtime::Runtime::new().unwrap();\n    let db = std::cell::RefCell::new(runtime.block_on(init_connection()));\n\n    c.bench_with_input(\n        BenchmarkId::new(\"insert\", \"returning\"),\n        &db,\n        move |b, db_ref| {\n            // Insert a call to `to_async` to convert the bencher to async mode.\n            // The timing loops are the same as with the normal bencher.\n            b.to_async(&runtime).iter(|| do_describe_insert(db_ref));\n        },\n    );\n}\n\nfn describe_insert_fks(c: &mut Criterion) {\n    let runtime = tokio::runtime::Runtime::new().unwrap();\n    let db = std::cell::RefCell::new(runtime.block_on(init_connection()));\n\n    c.bench_with_input(BenchmarkId::new(\"insert\", \"fks\"), &db, move |b, db_ref| {\n        // Insert a call to `to_async` to convert the bencher to async mode.\n        // The timing loops are the same as with the normal bencher.\n        b.to_async(&runtime).iter(|| do_describe_insert_fks(db_ref));\n    });\n}\n\ncriterion_group!(\n    benches,\n    describe_trivial,\n    describe_recursive,\n    describe_insert,\n    describe_insert_fks\n);\ncriterion_main!(benches);\n"
  },
  {
    "path": "clippy.toml",
    "content": "[[disallowed-methods]]\npath = \"core::cmp::Ord::min\"\nreason = '''\ntoo easy to misread `x.min(y)` as \"let the minimum value of `x` be `y`\" when it actually means the exact opposite;\nuse `std::cmp::min` instead.\n'''\n\n[[disallowed-methods]]\npath = \"core::cmp::Ord::max\"\nreason = '''\ntoo easy to misread `x.max(y)` as \"let the maximum value of `x` be `y`\" when it actually means the exact opposite;\nuse `std::cmp::max` instead.\n'''\n"
  },
  {
    "path": "contrib/ide/vscode/settings.json",
    "content": "{\n    \"rust-analyzer.assist.importMergeBehaviour\": \"last\"\n}\n"
  },
  {
    "path": "examples/.gitignore",
    "content": "sqlite/todos/todos.db\n"
  },
  {
    "path": "examples/mysql/todos/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-mysql-todos\"\nversion = \"0.1.0\"\nedition = \"2021\"\nworkspace = \"../../../\"\n\n[dependencies]\nanyhow = \"1.0\"\nsqlx = { path = \"../../../\", features = [ \"mysql\", \"runtime-tokio\", \"tls-native-tls\" ] }\nclap = { version = \"4\", features = [\"derive\"] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\n"
  },
  {
    "path": "examples/mysql/todos/README.md",
    "content": "# TODOs Example\n\n## Setup\n\n1. Declare the database URL\n\n    ```\n    export DATABASE_URL=\"mysql://root:password@localhost/todos\"\n    ```\n\n2. Create the database.\n\n    ```\n    $ sqlx db create\n    ```\n\n3. Run sql migrations\n\n    ```\n    $ sqlx migrate run\n    ```\n\n## Usage\n\nAdd a todo \n\n```\ncargo run -- add \"todo description\"\n```\n\nComplete a todo.\n\n```\ncargo run -- done <todo id>\n```\n\nList all todos\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/mysql/todos/migrations/20200718111257_todos.sql",
    "content": "CREATE TABLE IF NOT EXISTS todos\n(\n    id          BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,\n    description TEXT    NOT NULL,\n    done        BOOLEAN NOT NULL DEFAULT FALSE\n);\n"
  },
  {
    "path": "examples/mysql/todos/src/main.rs",
    "content": "use clap::{Parser, Subcommand};\nuse sqlx::mysql::MySqlPool;\nuse std::env;\n\n#[derive(Parser)]\nstruct Args {\n    #[command(subcommand)]\n    cmd: Option<Command>,\n}\n\n#[derive(Subcommand)]\nenum Command {\n    Add { description: String },\n    Done { id: u64 },\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    let args = Args::parse();\n    let pool = MySqlPool::connect(&env::var(\"DATABASE_URL\")?).await?;\n\n    match args.cmd {\n        Some(Command::Add { description }) => {\n            println!(\"Adding new todo with description '{description}'\");\n            let todo_id = add_todo(&pool, description).await?;\n            println!(\"Added new todo with id {todo_id}\");\n        }\n        Some(Command::Done { id }) => {\n            println!(\"Marking todo {id} as done\");\n            if complete_todo(&pool, id).await? {\n                println!(\"Todo {id} is marked as done\");\n            } else {\n                println!(\"Invalid id {id}\");\n            }\n        }\n        None => {\n            println!(\"Printing list of all todos\");\n            list_todos(&pool).await?;\n        }\n    }\n\n    Ok(())\n}\n\nasync fn add_todo(pool: &MySqlPool, description: String) -> anyhow::Result<u64> {\n    // Insert the task, then obtain the ID of this row\n    let todo_id = sqlx::query!(\n        r#\"\nINSERT INTO todos ( description )\nVALUES ( ? )\n        \"#,\n        description\n    )\n    .execute(pool)\n    .await?\n    .last_insert_id();\n\n    Ok(todo_id)\n}\n\nasync fn complete_todo(pool: &MySqlPool, id: u64) -> anyhow::Result<bool> {\n    let rows_affected = sqlx::query!(\n        r#\"\nUPDATE todos\nSET done = TRUE\nWHERE id = ?\n        \"#,\n        id\n    )\n    .execute(pool)\n    .await?\n    .rows_affected();\n\n    Ok(rows_affected > 0)\n}\n\nasync fn list_todos(pool: &MySqlPool) -> anyhow::Result<()> {\n    let recs = sqlx::query!(\n        r#\"\nSELECT id, description, done\nFROM todos\nORDER BY id\n        \"#\n    )\n    .fetch_all(pool)\n    .await?;\n\n    // NOTE: Booleans in MySQL are stored as `TINYINT(1)` / `i8`\n    //       0 = false, non-0 = true\n    for rec in recs {\n        println!(\n            \"- [{}] {}: {}\",\n            if rec.done != 0 { \"x\" } else { \" \" },\n            rec.id,\n            &rec.description,\n        );\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-axum-social\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\n# Primary crates\naxum = { version = \"0.5.13\", features = [\"macros\"] }\nsqlx = { path = \"../../../\", features = [ \"runtime-tokio\", \"tls-rustls-ring\", \"postgres\", \"time\", \"uuid\" ] }\ntokio = { version = \"1.20.1\", features = [\"rt-multi-thread\", \"macros\"] }\n\n# Important secondary crates\nargon2 = \"0.4.1\"\nrand = \"0.8.5\"\nregex = \"1.6.0\"\nserde = \"1.0.140\"\nserde_with = { version = \"2.0.0\", features = [\"time_0_3\"] }\ntime = \"0.3.11\"\nuuid = { version = \"1.1.2\", features = [\"serde\"] }\nvalidator = { version = \"0.16.0\", features = [\"derive\"] }\n\n# Auxilliary crates\nanyhow = \"1.0.58\"\ndotenvy = \"0.15.1\"\nthiserror = \"2.0.0\"\ntracing = \"0.1.35\"\n\n[dev-dependencies]\nserde_json = \"1.0.82\"\ntower = \"0.4.13\"\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/README.md",
    "content": "This example demonstrates how to write integration tests for an API build with [Axum] and SQLx using `#[sqlx::test]`.\n\nSee also: https://github.com/tokio-rs/axum/blob/main/examples/testing\n\n# Warning\n\nFor the sake of brevity, this project omits numerous critical security precautions. You can use it as a starting point,\nbut deploy to production at your own risk!\n\n[Axum]: https://github.com/tokio-rs/axum\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/migrations/1_user.sql",
    "content": "create table \"user\"\n(\n    user_id       uuid primary key default gen_random_uuid(),\n    username      text unique not null,\n    password_hash text        not null\n);\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/migrations/2_post.sql",
    "content": "create table post (\n    post_id uuid primary key default gen_random_uuid(),\n    user_id uuid not null references \"user\"(user_id),\n    content text not null,\n    created_at timestamptz not null default now()\n);\n\ncreate index on post(created_at desc);\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/migrations/3_comment.sql",
    "content": "create table comment (\n    comment_id uuid primary key default gen_random_uuid(),\n    post_id uuid not null references post(post_id),\n    user_id uuid not null references \"user\"(user_id),\n    content text not null,\n    created_at timestamptz not null default now()\n);\n\ncreate index on comment(post_id, created_at);\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/http/error.rs",
    "content": "use axum::http::StatusCode;\nuse axum::response::{IntoResponse, Response};\nuse axum::Json;\n\nuse serde_with::DisplayFromStr;\nuse validator::ValidationErrors;\n\n/// An API-friendly error type.\n#[derive(thiserror::Error, Debug)]\npub enum Error {\n    /// A SQLx call returned an error.\n    ///\n    /// The exact error contents are not reported to the user in order to avoid leaking\n    /// information about database internals.\n    #[error(\"an internal database error occurred\")]\n    Sqlx(#[from] sqlx::Error),\n\n    /// Similarly, we don't want to report random `anyhow` errors to the user.\n    #[error(\"an internal server error occurred\")]\n    Anyhow(#[from] anyhow::Error),\n\n    #[error(\"validation error in request body\")]\n    InvalidEntity(#[from] ValidationErrors),\n\n    #[error(\"{0}\")]\n    UnprocessableEntity(String),\n\n    #[error(\"{0}\")]\n    Conflict(String),\n}\n\nimpl IntoResponse for Error {\n    fn into_response(self) -> Response {\n        #[serde_with::serde_as]\n        #[serde_with::skip_serializing_none]\n        #[derive(serde::Serialize)]\n        struct ErrorResponse<'a> {\n            // Serialize the `Display` output as the error message\n            #[serde_as(as = \"DisplayFromStr\")]\n            message: &'a Error,\n\n            errors: Option<&'a ValidationErrors>,\n        }\n\n        let errors = match &self {\n            Error::InvalidEntity(errors) => Some(errors),\n            _ => None,\n        };\n\n        // Normally you wouldn't just print this, but it's useful for debugging without\n        // using a logging framework.\n        println!(\"API error: {self:?}\");\n\n        (\n            self.status_code(),\n            Json(ErrorResponse {\n                message: &self,\n                errors,\n            }),\n        )\n            .into_response()\n    }\n}\n\nimpl Error {\n    fn status_code(&self) -> StatusCode {\n        use Error::*;\n\n        match self {\n            Sqlx(_) | Anyhow(_) => StatusCode::INTERNAL_SERVER_ERROR,\n            InvalidEntity(_) | UnprocessableEntity(_) => StatusCode::UNPROCESSABLE_ENTITY,\n            Conflict(_) => StatusCode::CONFLICT,\n        }\n    }\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/http/mod.rs",
    "content": "use anyhow::Context;\nuse axum::{Extension, Router};\nuse sqlx::PgPool;\n\nmod error;\n\nmod post;\nmod user;\n\npub use self::error::Error;\n\npub type Result<T, E = Error> = ::std::result::Result<T, E>;\n\npub fn app(db: PgPool) -> Router {\n    Router::new()\n        .merge(user::router())\n        .merge(post::router())\n        .layer(Extension(db))\n}\n\npub async fn serve(db: PgPool) -> anyhow::Result<()> {\n    axum::Server::bind(&\"0.0.0.0:8080\".parse().unwrap())\n        .serve(app(db).into_make_service())\n        .await\n        .context(\"failed to serve API\")\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/http/post/comment.rs",
    "content": "use axum::extract::Path;\nuse axum::{Extension, Json, Router};\n\nuse axum::routing::get;\n\nuse serde::{Deserialize, Serialize};\nuse time::OffsetDateTime;\n\nuse crate::http::user::UserAuth;\nuse sqlx::PgPool;\nuse validator::Validate;\n\nuse crate::http::Result;\n\nuse time::format_description::well_known::Rfc3339;\nuse uuid::Uuid;\n\npub fn router() -> Router {\n    Router::new().route(\n        \"/v1/post/:postId/comment\",\n        get(get_post_comments).post(create_post_comment),\n    )\n}\n\n#[derive(Deserialize, Validate)]\n#[serde(rename_all = \"camelCase\")]\nstruct CreateCommentRequest {\n    auth: UserAuth,\n    #[validate(length(min = 1, max = 1000))]\n    content: String,\n}\n\n#[serde_with::serde_as]\n#[derive(Serialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct Comment {\n    comment_id: Uuid,\n    username: String,\n    content: String,\n    // `OffsetDateTime`'s default serialization format is not standard.\n    #[serde_as(as = \"Rfc3339\")]\n    created_at: OffsetDateTime,\n}\n\n// #[axum::debug_handler] // very useful!\nasync fn create_post_comment(\n    db: Extension<PgPool>,\n    Path(post_id): Path<Uuid>,\n    Json(req): Json<CreateCommentRequest>,\n) -> Result<Json<Comment>> {\n    req.validate()?;\n    let user_id = req.auth.verify(&*db).await?;\n\n    let comment = sqlx::query_as!(\n        Comment,\n        // language=PostgreSQL\n        r#\"\n            with inserted_comment as (\n                insert into comment(user_id, post_id, content)\n                values ($1, $2, $3)\n                returning comment_id, user_id, content, created_at\n            )\n            select comment_id, username, content, created_at\n            from inserted_comment\n            inner join \"user\" using (user_id)\n        \"#,\n        user_id,\n        post_id,\n        req.content\n    )\n    .fetch_one(&*db)\n    .await?;\n\n    Ok(Json(comment))\n}\n\n/// Returns comments in ascending chronological order.\nasync fn get_post_comments(\n    db: Extension<PgPool>,\n    Path(post_id): Path<Uuid>,\n) -> Result<Json<Vec<Comment>>> {\n    // Note: normally you'd want to put a `LIMIT` on this as well,\n    // though that would also necessitate implementing pagination.\n    let comments = sqlx::query_as!(\n        Comment,\n        // language=PostgreSQL\n        r#\"\n            select comment_id, username, content, created_at\n            from comment\n            inner join \"user\" using (user_id)\n            where post_id = $1\n            order by created_at\n        \"#,\n        post_id\n    )\n    .fetch_all(&*db)\n    .await?;\n\n    Ok(Json(comments))\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/http/post/mod.rs",
    "content": "use axum::{Extension, Json, Router};\n\nuse axum::routing::get;\n\nuse serde::{Deserialize, Serialize};\nuse time::OffsetDateTime;\n\nuse crate::http::user::UserAuth;\nuse sqlx::PgPool;\nuse validator::Validate;\n\nuse crate::http::Result;\n\nuse time::format_description::well_known::Rfc3339;\nuse uuid::Uuid;\n\nmod comment;\n\npub fn router() -> Router {\n    Router::new()\n        .route(\"/v1/post\", get(get_posts).post(create_post))\n        .merge(comment::router())\n}\n\n#[derive(Deserialize, Validate)]\n#[serde(rename_all = \"camelCase\")]\nstruct CreatePostRequest {\n    auth: UserAuth,\n    #[validate(length(min = 1, max = 1000))]\n    content: String,\n}\n\n#[serde_with::serde_as]\n#[derive(Serialize)]\n#[serde(rename_all = \"camelCase\")]\nstruct Post {\n    post_id: Uuid,\n    username: String,\n    content: String,\n    // `OffsetDateTime`'s default serialization format is not standard.\n    #[serde_as(as = \"Rfc3339\")]\n    created_at: OffsetDateTime,\n}\n\n// #[axum::debug_handler] // very useful!\nasync fn create_post(\n    db: Extension<PgPool>,\n    Json(req): Json<CreatePostRequest>,\n) -> Result<Json<Post>> {\n    req.validate()?;\n    let user_id = req.auth.verify(&*db).await?;\n\n    let post = sqlx::query_as!(\n        Post,\n        // language=PostgreSQL\n        r#\"\n            with inserted_post as (\n                insert into post(user_id, content)\n                values ($1, $2)\n                returning post_id, user_id, content, created_at\n            )\n            select post_id, username, content, created_at\n            from inserted_post\n            inner join \"user\" using (user_id)\n        \"#,\n        user_id,\n        req.content\n    )\n    .fetch_one(&*db)\n    .await?;\n\n    Ok(Json(post))\n}\n\n/// Returns posts in descending chronological order.\nasync fn get_posts(db: Extension<PgPool>) -> Result<Json<Vec<Post>>> {\n    // Note: normally you'd want to put a `LIMIT` on this as well,\n    // though that would also necessitate implementing pagination.\n    let posts = sqlx::query_as!(\n        Post,\n        // language=PostgreSQL\n        r#\"\n            select post_id, username, content, created_at\n            from post\n            inner join \"user\" using (user_id)\n            order by created_at desc\n        \"#\n    )\n    .fetch_all(&*db)\n    .await?;\n\n    Ok(Json(posts))\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/http/user.rs",
    "content": "use axum::http::StatusCode;\nuse axum::{routing::post, Extension, Json, Router};\nuse rand::Rng;\nuse regex::Regex;\nuse std::{sync::LazyLock, time::Duration};\n\nuse serde::Deserialize;\nuse sqlx::{PgExecutor, PgPool};\nuse uuid::Uuid;\nuse validator::Validate;\n\nuse crate::http::{Error, Result};\n\npub type UserId = Uuid;\n\npub fn router() -> Router {\n    Router::new().route(\"/v1/user\", post(create_user))\n}\n\nstatic USERNAME_REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new(r\"^[0-9A-Za-z_]+$\").unwrap());\n\n// CREATE USER\n\n#[derive(Deserialize, Validate)]\n#[serde(rename_all = \"camelCase\")]\npub struct UserAuth {\n    #[validate(length(min = 3, max = 16), regex = \"USERNAME_REGEX\")]\n    username: String,\n    #[validate(length(min = 8, max = 32))]\n    password: String,\n}\n\n// WARNING: this API has none of the checks that a normal user signup flow implements,\n// such as email or phone verification.\nasync fn create_user(db: Extension<PgPool>, Json(req): Json<UserAuth>) -> Result<StatusCode> {\n    req.validate()?;\n\n    let UserAuth { username, password } = req;\n\n    // It would be irresponsible to store passwords in plaintext, however.\n    let password_hash = crate::password::hash(password).await?;\n\n    sqlx::query!(\n        // language=PostgreSQL\n        r#\"\n            insert into \"user\"(username, password_hash)\n            values ($1, $2)\n        \"#,\n        username,\n        password_hash\n    )\n    .execute(&*db)\n    .await\n    .map_err(|e| match e {\n        sqlx::Error::Database(dbe) if dbe.constraint() == Some(\"user_username_key\") => {\n            Error::Conflict(\"username taken\".into())\n        }\n        _ => e.into(),\n    })?;\n\n    Ok(StatusCode::NO_CONTENT)\n}\n\nimpl UserAuth {\n    // NOTE: normally we wouldn't want to verify the username and password every time,\n    // but persistent sessions would have complicated the example.\n    pub async fn verify(self, db: impl PgExecutor<'_> + Send) -> Result<UserId> {\n        self.validate()?;\n\n        let maybe_user = sqlx::query!(\n            r#\"select user_id, password_hash from \"user\" where username = $1\"#,\n            self.username\n        )\n        .fetch_optional(db)\n        .await?;\n\n        if let Some(user) = maybe_user {\n            let verified = crate::password::verify(self.password, user.password_hash).await?;\n\n            if verified {\n                return Ok(user.user_id);\n            }\n        }\n\n        // Sleep a random amount of time to avoid leaking existence of a user in timing.\n        let sleep_duration =\n            rand::thread_rng().gen_range(Duration::from_millis(100)..=Duration::from_millis(500));\n        tokio::time::sleep(sleep_duration).await;\n\n        Err(Error::UnprocessableEntity(\n            \"invalid username/password\".into(),\n        ))\n    }\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/lib.rs",
    "content": "pub mod http;\n\nmod password;\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/main.rs",
    "content": "use anyhow::Context;\nuse sqlx::postgres::PgPoolOptions;\n\n#[tokio::main]\nasync fn main() -> anyhow::Result<()> {\n    let database_url = dotenvy::var(\"DATABASE_URL\")\n        // The error from `var()` doesn't mention the environment variable.\n        .context(\"DATABASE_URL must be set\")?;\n\n    let db = PgPoolOptions::new()\n        .max_connections(20)\n        .connect(&database_url)\n        .await\n        .context(\"failed to connect to DATABASE_URL\")?;\n\n    sqlx::migrate!().run(&db).await?;\n\n    sqlx_example_postgres_axum_social::http::serve(db).await\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/src/password.rs",
    "content": "use anyhow::{anyhow, Context};\nuse tokio::task;\n\nuse argon2::password_hash::SaltString;\nuse argon2::{password_hash, Argon2, PasswordHash, PasswordHasher, PasswordVerifier};\n\npub async fn hash(password: String) -> anyhow::Result<String> {\n    task::spawn_blocking(move || {\n        let salt = SaltString::generate(rand::thread_rng());\n        Ok(Argon2::default()\n            .hash_password(password.as_bytes(), &salt)\n            .map_err(|e| anyhow!(e).context(\"failed to hash password\"))?\n            .to_string())\n    })\n    .await\n    .context(\"panic in hash()\")?\n}\n\npub async fn verify(password: String, hash: String) -> anyhow::Result<bool> {\n    task::spawn_blocking(move || {\n        let hash = PasswordHash::new(&hash)\n            .map_err(|e| anyhow!(e).context(\"BUG: password hash invalid\"))?;\n\n        let res = Argon2::default().verify_password(password.as_bytes(), &hash);\n\n        match res {\n            Ok(()) => Ok(true),\n            Err(password_hash::Error::Password) => Ok(false),\n            Err(e) => Err(anyhow!(e).context(\"failed to verify password\")),\n        }\n    })\n    .await\n    .context(\"panic in verify()\")?\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/comment.rs",
    "content": "use sqlx::PgPool;\n\nuse sqlx_example_postgres_axum_social::http;\n\nuse axum::http::{Request, StatusCode};\nuse tower::ServiceExt;\n\nuse std::borrow::BorrowMut;\n\nuse common::{expect_rfc3339_timestamp, expect_uuid, response_json, RequestBuilderExt};\n\nuse serde_json::json;\n\nmod common;\n\n#[sqlx::test(fixtures(\"users\", \"posts\"))]\nasync fn test_create_comment(db: PgPool) {\n    let mut app = http::app(db);\n\n    // Happy path!\n    let mut resp1 = app\n        .borrow_mut()\n        .oneshot(\n            Request::post(\"/v1/post/d9ca2672-24c5-4442-b32f-cd717adffbaa/comment\").json(json! {\n                {\n                    \"auth\": {\n                        \"username\": \"bob\",\n                        \"password\": \"pro gamer 1990\"\n                    },\n                    \"content\": \"lol bet ur still bad, 1v1 me\"\n                }\n            }),\n        )\n        .await\n        .unwrap();\n\n    assert_eq!(resp1.status(), StatusCode::OK);\n\n    let resp1_json = response_json(&mut resp1).await;\n\n    assert_eq!(resp1_json[\"username\"], \"bob\");\n    assert_eq!(resp1_json[\"content\"], \"lol bet ur still bad, 1v1 me\");\n\n    let _comment_id = expect_uuid(&resp1_json[\"commentId\"]);\n\n    let _created_at = expect_rfc3339_timestamp(&resp1_json[\"createdAt\"]);\n\n    // Incorrect username\n    let mut resp2 = app\n        .borrow_mut()\n        .oneshot(\n            Request::post(\"/v1/post/d9ca2672-24c5-4442-b32f-cd717adffbaa/comment\").json(json! {\n                {\n                    \"auth\": {\n                        \"username\": \"bobbbbbb\",\n                        \"password\": \"pro gamer 1990\"\n                    },\n                    \"content\": \"lol bet ur still bad, 1v1 me\"\n                }\n            }),\n        )\n        .await\n        .unwrap();\n\n    assert_eq!(resp2.status(), StatusCode::UNPROCESSABLE_ENTITY);\n\n    let resp2_json = response_json(&mut resp2).await;\n    assert_eq!(resp2_json[\"message\"], \"invalid username/password\");\n\n    // Incorrect password\n    let mut resp3 = app\n        .borrow_mut()\n        .oneshot(\n            Request::post(\"/v1/post/d9ca2672-24c5-4442-b32f-cd717adffbaa/comment\").json(json! {\n                {\n                    \"auth\": {\n                        \"username\": \"bob\",\n                        \"password\": \"pro    gamer     1990\"\n                    },\n                    \"content\": \"lol bet ur still bad, 1v1 me\"\n                }\n            }),\n        )\n        .await\n        .unwrap();\n\n    assert_eq!(resp3.status(), StatusCode::UNPROCESSABLE_ENTITY);\n\n    let resp3_json = response_json(&mut resp3).await;\n    assert_eq!(resp3_json[\"message\"], \"invalid username/password\");\n}\n\n#[sqlx::test(fixtures(\"users\", \"posts\", \"comments\"))]\nasync fn test_list_comments(db: PgPool) {\n    let mut app = http::app(db);\n\n    // This only has the happy path.\n    let mut resp = app\n        .borrow_mut()\n        .oneshot(Request::get(\"/v1/post/d9ca2672-24c5-4442-b32f-cd717adffbaa/comment\").empty_body())\n        .await\n        .unwrap();\n\n    assert_eq!(resp.status(), StatusCode::OK);\n\n    let resp_json = response_json(&mut resp).await;\n\n    let comments = resp_json\n        .as_array()\n        .expect(\"expected request to return an array\");\n\n    assert_eq!(comments.len(), 2);\n\n    assert_eq!(comments[0][\"username\"], \"bob\");\n    assert_eq!(comments[0][\"content\"], \"lol bet ur still bad, 1v1 me\");\n\n    let _comment_id = expect_uuid(&comments[0][\"commentId\"]);\n    let created_at_0 = expect_rfc3339_timestamp(&comments[0][\"createdAt\"]);\n\n    assert_eq!(comments[1][\"username\"], \"alice\");\n    assert_eq!(comments[1][\"content\"], \"you're on!\");\n\n    let _comment_id = expect_uuid(&comments[1][\"commentId\"]);\n    let created_at_1 = expect_rfc3339_timestamp(&comments[1][\"createdAt\"]);\n\n    assert!(\n        created_at_0 < created_at_1,\n        \"comments must be assorted in ascending order\"\n    );\n\n    let mut resp = app\n        .borrow_mut()\n        .oneshot(Request::get(\"/v1/post/7e3d4d16-a35e-46ba-8223-b4f1debbfbfe/comment\").empty_body())\n        .await\n        .unwrap();\n\n    assert_eq!(resp.status(), StatusCode::OK);\n\n    let resp_json = response_json(&mut resp).await;\n\n    let comments = resp_json\n        .as_array()\n        .expect(\"expected request to return an array\");\n\n    assert_eq!(comments.len(), 1);\n\n    assert_eq!(comments[0][\"username\"], \"alice\");\n    assert_eq!(comments[0][\"content\"], \"lol you're just mad you lost :P\");\n\n    let _comment_id = expect_uuid(&comments[0][\"commentId\"]);\n    let _created_at = expect_rfc3339_timestamp(&comments[0][\"createdAt\"]);\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/common.rs",
    "content": "// This is imported by different tests that use different functions.\n#![allow(dead_code)]\n\nuse axum::body::{Body, BoxBody, HttpBody};\nuse axum::http::header::CONTENT_TYPE;\nuse axum::http::{request, Request};\nuse axum::response::Response;\nuse time::format_description::well_known::Rfc3339;\nuse time::OffsetDateTime;\nuse uuid::Uuid;\n\npub trait RequestBuilderExt {\n    fn json(self, json: serde_json::Value) -> Request<Body>;\n\n    fn empty_body(self) -> Request<Body>;\n}\n\nimpl RequestBuilderExt for request::Builder {\n    fn json(self, json: serde_json::Value) -> Request<Body> {\n        self.header(\"Content-Type\", \"application/json\")\n            .body(Body::from(json.to_string()))\n            .expect(\"failed to build request\")\n    }\n\n    fn empty_body(self) -> Request<Body> {\n        self.body(Body::empty()).expect(\"failed to build request\")\n    }\n}\n\npub async fn response_json(resp: &mut Response<BoxBody>) -> serde_json::Value {\n    assert_eq!(\n        resp.headers()\n            .get(CONTENT_TYPE)\n            .expect(\"expected Content-Type\"),\n        \"application/json\"\n    );\n\n    let body = resp.body_mut();\n\n    let mut bytes = Vec::new();\n\n    while let Some(res) = body.data().await {\n        let chunk = res.expect(\"error reading response body\");\n\n        bytes.extend_from_slice(&chunk[..]);\n    }\n\n    serde_json::from_slice(&bytes).expect(\"failed to read response body as json\")\n}\n\n#[track_caller]\npub fn expect_string(value: &serde_json::Value) -> &str {\n    value\n        .as_str()\n        .unwrap_or_else(|| panic!(\"expected string, got {value:?}\"))\n}\n\n#[track_caller]\npub fn expect_uuid(value: &serde_json::Value) -> Uuid {\n    expect_string(value)\n        .parse::<Uuid>()\n        .unwrap_or_else(|e| panic!(\"failed to parse UUID from {value:?}: {e}\"))\n}\n\n#[track_caller]\npub fn expect_rfc3339_timestamp(value: &serde_json::Value) -> OffsetDateTime {\n    let s = expect_string(value);\n\n    OffsetDateTime::parse(s, &Rfc3339)\n        .unwrap_or_else(|e| panic!(\"failed to parse RFC-3339 timestamp from {value:?}: {e}\"))\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/fixtures/comments.sql",
    "content": "INSERT INTO public.comment (comment_id, post_id, user_id, content, created_at)\nVALUES\n    -- from: bob\n    ('3a86b8f8-827b-4f14-94a2-34517b4b5bde', 'd9ca2672-24c5-4442-b32f-cd717adffbaa',\n     'c994b839-84f4-4509-ad49-59119133d6f5', 'lol bet ur still bad, 1v1 me', '2022-07-29 01:52:31.167673'),\n    -- from: alice\n    ('d6f862b5-2b87-4af4-b15e-6b3398729e6d', 'd9ca2672-24c5-4442-b32f-cd717adffbaa',\n     '51b374f1-93ae-4c5c-89dd-611bda8412ce', 'you''re on!', '2022-07-29 01:53:53.115782'),\n    -- from: alice\n    ('1eed85ae-adae-473c-8d05-b1dae0a1df63', '7e3d4d16-a35e-46ba-8223-b4f1debbfbfe',\n     '51b374f1-93ae-4c5c-89dd-611bda8412ce', 'lol you''re just mad you lost :P', '2022-07-29 01:55:50.116119');\n\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/fixtures/posts.sql",
    "content": "INSERT INTO public.post (post_id, user_id, content, created_at)\nVALUES\n    -- from: alice\n    ('d9ca2672-24c5-4442-b32f-cd717adffbaa', '51b374f1-93ae-4c5c-89dd-611bda8412ce',\n     'This new computer is blazing fast!', '2022-07-29 01:36:24.679082'),\n    -- from: bob\n    ('7e3d4d16-a35e-46ba-8223-b4f1debbfbfe', 'c994b839-84f4-4509-ad49-59119133d6f5', '@alice is a haxxor',\n     '2022-07-29 01:54:45.823523');\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/fixtures/users.sql",
    "content": "INSERT INTO public.\"user\" (user_id, username, password_hash)\nVALUES\n    -- username: \"alice\"; password: \"rustacean since 2015\"\n    ('51b374f1-93ae-4c5c-89dd-611bda8412ce', 'alice',\n     '$argon2id$v=19$m=4096,t=3,p=1$3v3ats/tYTXAYs3q9RycDw$ZltwjS3oQwPuNmL9f6DNb+sH5N81dTVZhVNbUQzmmVU'),\n    -- username: \"bob\"; password: \"pro gamer 1990\"\n    ('c994b839-84f4-4509-ad49-59119133d6f5', 'bob',\n     '$argon2id$v=19$m=4096,t=3,p=1$1zbkRinUH9WHzkyu8C1Vlg$70pu5Cca/s3d0nh5BYQGkN7+s9cqlNxTE7rFZaUaP4c');\n\n\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/post.rs",
    "content": "use sqlx::PgPool;\n\nuse sqlx_example_postgres_axum_social::http;\n\nuse axum::http::{Request, StatusCode};\nuse tower::ServiceExt;\n\nuse std::borrow::BorrowMut;\n\nuse common::{expect_rfc3339_timestamp, expect_uuid, response_json, RequestBuilderExt};\n\nuse serde_json::json;\n\nmod common;\n\n#[sqlx::test(fixtures(\"users\"))]\nasync fn test_create_post(db: PgPool) {\n    let mut app = http::app(db);\n\n    // Happy path!\n    let mut resp1 = app\n        .borrow_mut()\n        .oneshot(Request::post(\"/v1/post\").json(json! {\n            {\n                \"auth\": {\n                    \"username\": \"alice\",\n                    \"password\": \"rustacean since 2015\"\n                },\n                \"content\": \"This new computer is blazing fast!\"\n            }\n        }))\n        .await\n        .unwrap();\n\n    assert_eq!(resp1.status(), StatusCode::OK);\n\n    let resp1_json = response_json(&mut resp1).await;\n\n    assert_eq!(resp1_json[\"username\"], \"alice\");\n    assert_eq!(resp1_json[\"content\"], \"This new computer is blazing fast!\");\n\n    let _post_id = expect_uuid(&resp1_json[\"postId\"]);\n    let _created_at = expect_rfc3339_timestamp(&resp1_json[\"createdAt\"]);\n\n    // Incorrect username\n    let mut resp2 = app\n        .borrow_mut()\n        .oneshot(Request::post(\"/v1/post\").json(json! {\n            {\n                \"auth\": {\n                    \"username\": \"aliceee\",\n                    \"password\": \"rustacean since 2015\"\n                },\n                \"content\": \"This new computer is blazing fast!\"\n            }\n        }))\n        .await\n        .unwrap();\n\n    assert_eq!(resp2.status(), StatusCode::UNPROCESSABLE_ENTITY);\n\n    let resp2_json = response_json(&mut resp2).await;\n    assert_eq!(resp2_json[\"message\"], \"invalid username/password\");\n\n    // Incorrect password\n    let mut resp3 = app\n        .borrow_mut()\n        .oneshot(Request::post(\"/v1/post\").json(json! {\n            {\n                \"auth\": {\n                    \"username\": \"alice\",\n                    \"password\": \"rustaceansince2015\"\n                },\n                \"content\": \"This new computer is blazing fast!\"\n            }\n        }))\n        .await\n        .unwrap();\n\n    assert_eq!(resp3.status(), StatusCode::UNPROCESSABLE_ENTITY);\n\n    let resp3_json = response_json(&mut resp3).await;\n    assert_eq!(resp3_json[\"message\"], \"invalid username/password\");\n}\n\n#[sqlx::test(fixtures(\"users\", \"posts\"))]\nasync fn test_list_posts(db: PgPool) {\n    // This only has the happy path.\n    let mut resp = http::app(db)\n        .oneshot(Request::get(\"/v1/post\").empty_body())\n        .await\n        .unwrap();\n\n    assert_eq!(resp.status(), StatusCode::OK);\n\n    let resp_json = response_json(&mut resp).await;\n\n    let posts = resp_json\n        .as_array()\n        .expect(\"expected GET /v1/post to return an array\");\n\n    assert_eq!(posts.len(), 2);\n\n    assert_eq!(posts[0][\"username\"], \"bob\");\n    assert_eq!(posts[0][\"content\"], \"@alice is a haxxor\");\n\n    let _post_id = expect_uuid(&posts[0][\"postId\"]);\n    let created_at_0 = expect_rfc3339_timestamp(&posts[0][\"createdAt\"]);\n\n    assert_eq!(posts[1][\"username\"], \"alice\");\n    assert_eq!(posts[1][\"content\"], \"This new computer is blazing fast!\");\n\n    let _post_id = expect_uuid(&posts[1][\"postId\"]);\n    let created_at_1 = expect_rfc3339_timestamp(&posts[1][\"createdAt\"]);\n\n    assert!(\n        created_at_0 > created_at_1,\n        \"posts must be sorted in descending order\"\n    );\n}\n"
  },
  {
    "path": "examples/postgres/axum-social-with-tests/tests/user.rs",
    "content": "use sqlx::PgPool;\n\nuse sqlx_example_postgres_axum_social::http;\n\nuse axum::http::{Request, StatusCode};\nuse tower::ServiceExt;\n\nuse std::borrow::BorrowMut;\n\nuse common::{response_json, RequestBuilderExt};\n\nuse serde_json::json;\n\nmod common;\n\n#[sqlx::test]\nasync fn test_create_user(db: PgPool) {\n    let mut app = http::app(db);\n\n    // Happy path!\n    let resp1 = app\n        .borrow_mut()\n        // We handle JSON objects directly to sanity check the serialization and deserialization\n        .oneshot(Request::post(\"/v1/user\").json(json! {{\n            \"username\": \"alice\",\n            \"password\": \"rustacean since 2015\"\n        }}))\n        .await\n        .unwrap();\n\n    assert_eq!(resp1.status(), StatusCode::NO_CONTENT);\n\n    // Username taken\n    let mut resp2 = app\n        .borrow_mut()\n        .oneshot(Request::post(\"/v1/user\").json(json! {{\n            \"username\": \"alice\",\n            \"password\": \"uhhh i forgot\"\n        }}))\n        .await\n        .unwrap();\n\n    assert_eq!(resp2.status(), StatusCode::CONFLICT);\n\n    let resp2_json = response_json(&mut resp2).await;\n    assert_eq!(resp2_json[\"message\"], \"username taken\");\n\n    // Invalid username\n    let mut resp3 = app\n        .borrow_mut()\n        .oneshot(Request::post(\"/v1/user\").json(json! {{\n            \"username\": \"definitely an invalid username\",\n            \"password\": \"password\"\n        }}))\n        .await\n        .unwrap();\n\n    assert_eq!(resp3.status(), StatusCode::UNPROCESSABLE_ENTITY);\n\n    let resp3_json = response_json(&mut resp3).await;\n\n    assert_eq!(resp3_json[\"message\"], \"validation error in request body\");\n    assert!(\n        resp3_json[\"errors\"][\"username\"].is_array(),\n        \"errors.username is not an array: {:?}\",\n        resp3_json\n    );\n\n    // Invalid password\n    let mut resp4 = app\n        .borrow_mut()\n        .oneshot(Request::post(\"/v1/user\").json(json! {{\n            \"username\": \"bobby123\",\n            \"password\": \"\"\n        }}))\n        .await\n        .unwrap();\n\n    assert_eq!(resp4.status(), StatusCode::UNPROCESSABLE_ENTITY);\n\n    let resp4_json = response_json(&mut resp4).await;\n\n    assert_eq!(resp4_json[\"message\"], \"validation error in request body\");\n    assert!(\n        resp4_json[\"errors\"][\"password\"].is_array(),\n        \"errors.password is not an array: {:?}\",\n        resp4_json\n    );\n}\n"
  },
  {
    "path": "examples/postgres/chat/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-chat\"\nversion = \"0.1.0\"\nedition = \"2021\"\nworkspace = \"../../../\"\n\n[dependencies]\nsqlx = { path = \"../../../\", features = [ \"postgres\", \"runtime-tokio\", \"tls-native-tls\" ] }\ntokio = { version = \"1.20.0\", features = [ \"rt-multi-thread\", \"macros\" ] }\nratatui = \"0.27.0\"\ncrossterm = \"0.27.0\"\nunicode-width = \"0.1\"\n"
  },
  {
    "path": "examples/postgres/chat/README.md",
    "content": "# Chat Example\n\nNote: this example has an interactive TUI which is not trivial to test automatically,\nso our CI currently only checks whether or not it compiles.\n\n## Description\n\nThis example demonstrates how to use PostgreSQL channels to create a very simple chat application.\n\n## Setup\n\n1. Declare the database URL\n\n    ```\n    export DATABASE_URL=\"postgres://postgres:password@localhost/files\"\n    ```\n\n## Usage\n\nRun the project\n\n```\ncargo run -p sqlx-examples-postgres-chat\n```\n"
  },
  {
    "path": "examples/postgres/chat/src/main.rs",
    "content": "use crossterm::{\n    event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode},\n    execute,\n    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},\n};\nuse ratatui::text::Line;\nuse ratatui::{\n    backend::{Backend, CrosstermBackend},\n    layout::{Constraint, Direction, Layout},\n    style::{Color, Modifier, Style},\n    text::{Span, Text},\n    widgets::{Block, Borders, List, ListItem, Paragraph},\n    Frame, Terminal,\n};\nuse sqlx::postgres::PgListener;\nuse sqlx::PgPool;\nuse std::sync::Arc;\nuse std::{error::Error, io};\nuse tokio::{sync::Mutex, time::Duration};\nuse unicode_width::UnicodeWidthStr;\n\nstruct ChatApp {\n    input: String,\n    messages: Arc<Mutex<Vec<String>>>,\n    pool: PgPool,\n}\n\nimpl ChatApp {\n    fn new(pool: PgPool) -> Self {\n        ChatApp {\n            input: String::new(),\n            messages: Arc::new(Mutex::new(Vec::new())),\n            pool,\n        }\n    }\n\n    async fn run<B: Backend>(\n        mut self,\n        terminal: &mut Terminal<B>,\n        mut listener: PgListener,\n    ) -> Result<(), Box<dyn Error>> {\n        // setup listener task\n        let messages = self.messages.clone();\n        tokio::spawn(async move {\n            while let Ok(msg) = listener.recv().await {\n                messages.lock().await.push(msg.payload().to_string());\n            }\n        });\n\n        loop {\n            let messages: Vec<ListItem> = self\n                .messages\n                .lock()\n                .await\n                .iter()\n                .map(|m| {\n                    let content = vec![Line::from(Span::raw(m.to_owned()))];\n                    ListItem::new(content)\n                })\n                .collect();\n\n            terminal.draw(|f| self.ui(f, messages))?;\n\n            if !event::poll(Duration::from_millis(20))? {\n                continue;\n            }\n\n            if let Event::Key(key) = event::read()? {\n                match key.code {\n                    KeyCode::Enter => {\n                        notify(&self.pool, &self.input).await?;\n                        self.input.clear();\n                    }\n                    KeyCode::Char(c) => {\n                        self.input.push(c);\n                    }\n                    KeyCode::Backspace => {\n                        self.input.pop();\n                    }\n                    KeyCode::Esc => {\n                        return Ok(());\n                    }\n                    _ => {}\n                }\n            }\n        }\n    }\n\n    fn ui(&mut self, frame: &mut Frame, messages: Vec<ListItem>) {\n        let chunks = Layout::default()\n            .direction(Direction::Vertical)\n            .margin(2)\n            .constraints(\n                [\n                    Constraint::Length(1),\n                    Constraint::Length(3),\n                    Constraint::Min(1),\n                ]\n                .as_ref(),\n            )\n            .split(frame.size());\n\n        let text = Text::from(Line::from(vec![\n            Span::raw(\"Press \"),\n            Span::styled(\"Enter\", Style::default().add_modifier(Modifier::BOLD)),\n            Span::raw(\" to send the message, \"),\n            Span::styled(\"Esc\", Style::default().add_modifier(Modifier::BOLD)),\n            Span::raw(\" to quit\"),\n        ]));\n        let help_message = Paragraph::new(text);\n        frame.render_widget(help_message, chunks[0]);\n\n        let input = Paragraph::new(self.input.as_str())\n            .style(Style::default().fg(Color::Yellow))\n            .block(Block::default().borders(Borders::ALL).title(\"Input\"));\n        frame.render_widget(input, chunks[1]);\n        frame.set_cursor(\n            // Put cursor past the end of the input text\n            chunks[1].x + self.input.width() as u16 + 1,\n            // Move one line down, from the border to the input line\n            chunks[1].y + 1,\n        );\n\n        let messages =\n            List::new(messages).block(Block::default().borders(Borders::ALL).title(\"Messages\"));\n        frame.render_widget(messages, chunks[2]);\n    }\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn Error>> {\n    // setup postgres\n    let conn_url =\n        std::env::var(\"DATABASE_URL\").expect(\"Env var DATABASE_URL is required for this example.\");\n    let pool = PgPool::connect(&conn_url).await?;\n\n    let mut listener = PgListener::connect(&conn_url).await?;\n    listener.listen(\"chan0\").await?;\n\n    // setup terminal\n    enable_raw_mode()?;\n    let mut stdout = io::stdout();\n    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;\n    let backend = CrosstermBackend::new(stdout);\n    let mut terminal = Terminal::new(backend)?;\n\n    // create app and run it\n    let app = ChatApp::new(pool);\n    let res = app.run(&mut terminal, listener).await;\n\n    // restore terminal\n    disable_raw_mode()?;\n    execute!(\n        terminal.backend_mut(),\n        LeaveAlternateScreen,\n        DisableMouseCapture,\n    )?;\n    terminal.show_cursor()?;\n\n    if let Err(err) = res {\n        println!(\"{err:?}\")\n    }\n\n    Ok(())\n}\n\nasync fn notify(pool: &PgPool, s: &str) -> Result<(), sqlx::Error> {\n    sqlx::query(\n        r#\"\nSELECT pg_notify(chan, payload)\nFROM (VALUES ('chan0', $1)) v(chan, payload)\n\"#,\n    )\n    .bind(s)\n    .execute(pool)\n    .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/files/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-files\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nanyhow = \"1.0\"\nsqlx = { path = \"../../../\", features = [ \"postgres\", \"runtime-tokio\", \"tls-native-tls\" ] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\ndotenvy = \"0.15.0\"\n"
  },
  {
    "path": "examples/postgres/files/README.md",
    "content": "# Query files Example\n\n## Description\n\nThis example demonstrates storing external files to use for querying data.\nEncapsulating your SQL queries can be helpful in several ways, assisting with intellisense,\netc.\n\n\n## Setup\n\n1. Declare the database URL\n\n    ```\n    export DATABASE_URL=\"postgres://postgres:password@localhost/files\"\n    ```\n\n2. Create the database.\n\n    ```\n    $ sqlx db create\n    ```\n\n3. Run sql migrations\n\n    ```\n    $ sqlx migrate run\n    ```\n\n## Usage\n\nRun the project\n\n```\ncargo run files\n```"
  },
  {
    "path": "examples/postgres/files/migrations/20220712221654_files.sql",
    "content": "CREATE TABLE IF NOT EXISTS users\n(\n    id       BIGSERIAL PRIMARY KEY,\n    username TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS posts\n(\n    id      BIGSERIAL PRIMARY KEY,\n    title   TEXT NOT NULL,\n    body    TEXT NOT NULL,\n    user_id BIGINT NOT NULL\n        REFERENCES users (id) ON DELETE CASCADE\n);\n"
  },
  {
    "path": "examples/postgres/files/queries/insert_seed_data.sql",
    "content": "-- seed some data to work with\nWITH inserted_users_cte AS (\n    INSERT INTO users (username)\n        VALUES ('user1'),\n               ('user2')\n        RETURNING id as \"user_id\"\n)\nINSERT INTO posts (title, body, user_id)\nVALUES ('user1 post1 title', 'user1 post1 body', (SELECT user_id FROM inserted_users_cte FETCH FIRST ROW ONLY)),\n       ('user1 post2 title', 'user1 post2 body', (SELECT user_id FROM inserted_users_cte FETCH FIRST ROW ONLY)),\n       ('user2 post1 title', 'user2 post2 body', (SELECT user_id FROM inserted_users_cte OFFSET 1 LIMIT 1));"
  },
  {
    "path": "examples/postgres/files/queries/list_all_posts.sql",
    "content": "SELECT p.id as \"post_id\",\n       p.title,\n       p.body,\n       u.id as \"author_id\",\n       u.username as \"author_username\"\nFROM users u\n         JOIN posts p on u.id = p.user_id;"
  },
  {
    "path": "examples/postgres/files/src/main.rs",
    "content": "use sqlx::{query_file, query_file_as, FromRow, PgPool};\nuse std::fmt::{Display, Formatter};\n\n#[derive(FromRow)]\nstruct PostWithAuthorQuery {\n    pub post_id: i64,\n    pub title: String,\n    pub body: String,\n    pub author_id: i64,\n    pub author_username: String,\n}\n\nimpl Display for PostWithAuthorQuery {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            r#\"\n            post_id: {},\n            title: {},\n            body: {},\n            author_id: {},\n            author_username: {}\n        \"#,\n            self.post_id, self.title, self.body, self.author_id, self.author_username\n        )\n    }\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    let pool = PgPool::connect(&dotenvy::var(\"DATABASE_URL\")?).await?;\n\n    // we can use a traditional wrapper around the `query!()` macro using files\n    query_file!(\"queries/insert_seed_data.sql\")\n        .execute(&pool)\n        .await?;\n\n    // we can also use `query_file_as!()` similarly to `query_as!()` to map our database models\n    let posts_with_authors = query_file_as!(PostWithAuthorQuery, \"queries/list_all_posts.sql\")\n        .fetch_all(&pool)\n        .await?;\n\n    for post_with_author in posts_with_authors {\n        println!(\"{post_with_author}\");\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/json/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-json\"\nversion = \"0.1.0\"\nedition = \"2021\"\nworkspace = \"../../../\"\n\n[dependencies]\nanyhow = \"1.0\"\ndotenvy = \"0.15.0\"\nserde = { version = \"1\", features = [\"derive\"] }\nserde_json = \"1\"\nsqlx = { path = \"../../../\", features = [ \"runtime-tokio\", \"postgres\", \"json\" ] }\nclap = { version = \"4\", features = [\"derive\"] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\n"
  },
  {
    "path": "examples/postgres/json/README.md",
    "content": "# JSON Example\n\n## Setup\n\n1. Declare the database URL\n\n    ```\n    export DATABASE_URL=\"postgres://postgres:password@localhost/json\"\n    ```\n\n2. Create the database.\n\n    ```\n    $ sqlx db create\n    ```\n\n3. Run sql migrations\n\n    ```\n    $ sqlx migrate run\n    ```\n\n## Usage\n\nAdd a person\n\n```\necho '{ \"name\": \"John Doe\", \"age\": 30 }' | cargo run -- add\n```\n\nor with extra keys\n\n```\necho '{ \"name\": \"Jane Doe\", \"age\": 25, \"array\": [\"string\", true, 0] }' | cargo run -- add\n```\n\nList all people\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/postgres/json/migrations/20200824190010_json.sql",
    "content": "CREATE TABLE IF NOT EXISTS people\n(\n    id     BIGSERIAL PRIMARY KEY,\n    person JSONB NOT NULL\n);\n"
  },
  {
    "path": "examples/postgres/json/src/main.rs",
    "content": "use clap::{Parser, Subcommand};\nuse serde::{Deserialize, Serialize};\nuse serde_json::{Map, Value};\nuse sqlx::postgres::PgPool;\nuse sqlx::types::Json;\nuse std::io::{self, Read};\nuse std::num::NonZeroU8;\n\n#[derive(Parser)]\nstruct Args {\n    #[clap(subcommand)]\n    cmd: Option<Command>,\n}\n\n#[derive(Subcommand)]\nenum Command {\n    Add,\n}\n\n#[derive(Deserialize, Serialize)]\nstruct Person {\n    name: String,\n    age: NonZeroU8,\n    #[serde(flatten)]\n    extra: Map<String, Value>,\n}\n\nstruct Row {\n    id: i64,\n    person: Json<Person>,\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    let args = Args::parse();\n    let pool = PgPool::connect(&dotenvy::var(\"DATABASE_URL\")?).await?;\n\n    match args.cmd {\n        Some(Command::Add) => {\n            let mut json = String::new();\n            io::stdin().read_to_string(&mut json)?;\n\n            let person: Person = serde_json::from_str(&json)?;\n            println!(\n                \"Adding new person: {}\",\n                &serde_json::to_string_pretty(&person)?\n            );\n\n            let person_id = add_person(&pool, person).await?;\n            println!(\"Added new person with ID {person_id}\");\n        }\n        None => {\n            println!(\"Printing all people\");\n            list_people(&pool).await?;\n        }\n    }\n\n    Ok(())\n}\n\nasync fn add_person(pool: &PgPool, person: Person) -> anyhow::Result<i64> {\n    let rec = sqlx::query!(\n        r#\"\nINSERT INTO people ( person )\nVALUES ( $1 )\nRETURNING id\n        \"#,\n        Json(person) as _\n    )\n    .fetch_one(pool)\n    .await?;\n\n    Ok(rec.id)\n}\n\nasync fn list_people(pool: &PgPool) -> anyhow::Result<()> {\n    let rows = sqlx::query_as!(\n        Row,\n        r#\"\nSELECT id, person as \"person: Json<Person>\"\nFROM people\nORDER BY id\n        \"#\n    )\n    .fetch_all(pool)\n    .await?;\n\n    for row in rows {\n        println!(\n            \"{}: {}\",\n            row.id,\n            &serde_json::to_string_pretty(&row.person)?\n        );\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/listen/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-listen\"\nversion = \"0.1.0\"\nedition = \"2021\"\nworkspace = \"../../../\"\n\n[dependencies]\nsqlx = { path = \"../../../\", features = [ \"runtime-tokio\", \"postgres\" ] }\nfutures-util = { version = \"0.3.1\", default-features = false }\ntokio = { version = \"1.20.0\", features = [\"rt-multi-thread\", \"macros\", \"time\"]}\n"
  },
  {
    "path": "examples/postgres/listen/README.md",
    "content": "Postgres LISTEN/NOTIFY\n======================\n\n## Usage\n\nDeclare the database URL. This example does not include any reading or writing of data.\n\n```\nexport DATABASE_URL=\"postgres://postgres@localhost/postgres\"\n```\n\nRun.\n\n```\ncargo run\n```\n\nThe example program should connect to the database, and create a LISTEN loop on a predefined set of channels. A NOTIFY task will be spawned which will connect to the same database and will emit notifications on a 5 second interval.\n"
  },
  {
    "path": "examples/postgres/listen/src/main.rs",
    "content": "use futures_util::TryStreamExt;\nuse sqlx::postgres::PgListener;\nuse sqlx::{Executor, PgPool};\nuse std::pin::pin;\nuse std::sync::atomic::{AtomicI64, Ordering};\nuse std::time::Duration;\n\n/// How long to sit in the listen loop before exiting.\n///\n/// This ensures the example eventually exits, which is required for automated testing.\nconst LISTEN_DURATION: Duration = Duration::from_secs(5);\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    println!(\"Building PG pool.\");\n    let conn_str =\n        std::env::var(\"DATABASE_URL\").expect(\"Env var DATABASE_URL is required for this example.\");\n    let pool = sqlx::PgPool::connect(&conn_str).await?;\n\n    let mut listener = PgListener::connect_with(&pool).await?;\n\n    let notify_pool = pool.clone();\n    let _t = tokio::spawn(async move {\n        let mut interval = tokio::time::interval(Duration::from_secs(2));\n\n        while !notify_pool.is_closed() {\n            interval.tick().await;\n            notify(&notify_pool).await;\n        }\n    });\n\n    println!(\"Starting LISTEN loop.\");\n\n    listener.listen_all(vec![\"chan0\", \"chan1\", \"chan2\"]).await?;\n\n    let mut counter = 0usize;\n    loop {\n        let notification = listener.recv().await?;\n        println!(\"[from recv]: {notification:?}\");\n\n        counter += 1;\n        if counter >= 3 {\n            break;\n        }\n    }\n\n    // Prove that we are buffering messages by waiting for 6 seconds\n    listener.execute(\"SELECT pg_sleep(6)\").await?;\n\n    let mut stream = listener.into_stream();\n\n    // `Sleep` must be pinned\n    let mut timeout = pin!(tokio::time::sleep(LISTEN_DURATION));\n\n    loop {\n        tokio::select! {\n            res = stream.try_next() => {\n                if let Some(notification) = res? {\n                    println!(\"[from stream]: {notification:?}\");\n                } else {\n                    break;\n                }\n            },\n            _ = timeout.as_mut() => {\n                // Don't run forever\n                break;\n            }\n        }\n    }\n\n    // The stream is holding one connection. It needs to be dropped to allow the connection to\n    // return to the pool, otherwise `pool.close()` would never return.\n    drop(stream);\n\n    pool.close().await;\n\n    Ok(())\n}\n\nasync fn notify(pool: &PgPool) {\n    static COUNTER: AtomicI64 = AtomicI64::new(0);\n\n    // There's two ways you can invoke `NOTIFY`:\n    //\n    // 1: `NOTIFY <channel>, '<payload>'` which cannot take bind parameters and\n    // <channel> is an identifier which is lowercased unless double-quoted\n    //\n    // 2: `SELECT pg_notify('<channel>', '<payload>')` which can take bind parameters\n    // and <channel> preserves its case\n    //\n    // We recommend #2 for consistency and usability.\n\n    // language=PostgreSQL\n    let res = sqlx::query(\n        r#\"\n-- this emits '{ \"payload\": N }' as the actual payload\nselect pg_notify(chan, json_build_object('payload', payload)::text)\nfrom (\n         values ('chan0', $1),\n                ('chan1', $2),\n                ('chan2', $3)\n     ) notifies(chan, payload)\n    \"#,\n    )\n    .bind(COUNTER.fetch_add(1, Ordering::SeqCst))\n    .bind(COUNTER.fetch_add(1, Ordering::SeqCst))\n    .bind(COUNTER.fetch_add(1, Ordering::SeqCst))\n    .execute(pool)\n    .await;\n\n    println!(\"[from notify]: {res:?}\");\n}\n"
  },
  {
    "path": "examples/postgres/mockable-todos/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-mockable-todos\"\nversion = \"0.1.0\"\nedition = \"2021\"\nworkspace = \"../../../\"\n\n[dependencies]\nanyhow = \"1.0\"\nsqlx = { path = \"../../../\", features = [ \"postgres\", \"runtime-tokio\", \"tls-native-tls\" ] }\nclap = { version = \"4\", features = [\"derive\"] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\ndotenvy = \"0.15.0\"\nasync-trait = \"0.1.41\"\nmockall = \"0.11\"\n"
  },
  {
    "path": "examples/postgres/mockable-todos/README.md",
    "content": "# Mockable TODOs Example\n\n## Description\n\nThis example is based on the ideas in [this blog post](https://medium.com/better-programming/structuring-rust-project-for-testability-18207b5d0243). The value here is that the business logic can be unit tested independently from the database layer. Otherwise it is identical to the todos example.\n\n## Setup\n\n1. Run `docker-compose up -d` to run Postgres in the background.\n\n2. Declare the database URL, either by exporting it:\n\n    ```\n    export DATABASE_URL=\"postgres://postgres:password@localhost/todos\"\n    ```\n\n    or by making a `.env` file:\n\n    ```\n    cp .env.example .env\n    ```\n\n3. Create the database.\n\n    ```\n    $ sqlx db create\n    ```\n\n4. Run sql migrations\n\n    ```\n    $ sqlx migrate run\n    ```\n\n## Usage\n\nAdd a todo\n\n```\ncargo run -- add \"todo description\"\n```\n\nComplete a todo.\n\n```\ncargo run -- done <todo id>\n```\n\nList all todos\n\n```\ncargo run\n```\n\n## Cleanup\n\nTo destroy the Postgres database, run:\n\n```\ndocker-compose down --volumes\n```\n"
  },
  {
    "path": "examples/postgres/mockable-todos/docker-compose.yml",
    "content": "version: \"3\"\n\nservices:\n  database:\n    image: \"postgres\"\n    ports:\n      - \"5432:5432\"\n    restart: always\n    environment:\n      - POSTGRES_USER=postgres\n      - POSTGRES_PASSWORD=password\n      - POSTGRES_DB=todos\n    volumes:\n      - database_data:/var/lib/postgresql/data\nvolumes:\n  database_data:\n    driver: local\n"
  },
  {
    "path": "examples/postgres/mockable-todos/migrations/20200718111257_todos.sql",
    "content": "CREATE TABLE IF NOT EXISTS todos\n(\n    id          BIGSERIAL PRIMARY KEY,\n    description TEXT    NOT NULL,\n    done        BOOLEAN NOT NULL DEFAULT FALSE\n);\n"
  },
  {
    "path": "examples/postgres/mockable-todos/src/main.rs",
    "content": "use async_trait::async_trait;\nuse clap::{Parser, Subcommand};\nuse sqlx::postgres::PgPool;\nuse std::{env, io::Write, sync::Arc};\n\n#[derive(Parser)]\nstruct Args {\n    #[command(subcommand)]\n    cmd: Option<Command>,\n}\n\n#[derive(Subcommand)]\nenum Command {\n    Add { description: String },\n    Done { id: i64 },\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    dotenvy::dotenv().ok();\n    let args = Args::parse();\n    let pool = PgPool::connect(&env::var(\"DATABASE_URL\")?).await?;\n    let todo_repo = PostgresTodoRepo::new(pool);\n    let mut writer = std::io::stdout();\n\n    handle_command(args, todo_repo, &mut writer).await\n}\n\nasync fn handle_command(\n    args: Args,\n    todo_repo: impl TodoRepo,\n    writer: &mut impl Write,\n) -> anyhow::Result<()> {\n    match args.cmd {\n        Some(Command::Add { description }) => {\n            writeln!(\n                writer,\n                \"Adding new todo with description '{}'\",\n                &description\n            )?;\n            let todo_id = todo_repo.add_todo(description).await?;\n            writeln!(writer, \"Added new todo with id {todo_id}\")?;\n        }\n        Some(Command::Done { id }) => {\n            writeln!(writer, \"Marking todo {id} as done\")?;\n            if todo_repo.complete_todo(id).await? {\n                writeln!(writer, \"Todo {id} is marked as done\")?;\n            } else {\n                writeln!(writer, \"Invalid id {id}\")?;\n            }\n        }\n        None => {\n            writeln!(writer, \"Printing list of all todos\")?;\n            todo_repo.list_todos().await?;\n        }\n    }\n\n    Ok(())\n}\n\n#[mockall::automock]\n#[async_trait]\npub trait TodoRepo {\n    async fn add_todo(&self, description: String) -> anyhow::Result<i64>;\n    async fn complete_todo(&self, id: i64) -> anyhow::Result<bool>;\n    async fn list_todos(&self) -> anyhow::Result<()>;\n}\n\nstruct PostgresTodoRepo {\n    pg_pool: Arc<PgPool>,\n}\n\nimpl PostgresTodoRepo {\n    fn new(pg_pool: PgPool) -> Self {\n        Self {\n            pg_pool: Arc::new(pg_pool),\n        }\n    }\n}\n\n#[async_trait]\nimpl TodoRepo for PostgresTodoRepo {\n    async fn add_todo(&self, description: String) -> anyhow::Result<i64> {\n        let rec = sqlx::query!(\n            r#\"\nINSERT INTO todos ( description )\nVALUES ( $1 )\nRETURNING id\n        \"#,\n            description\n        )\n        .fetch_one(&*self.pg_pool)\n        .await?;\n\n        Ok(rec.id)\n    }\n\n    async fn complete_todo(&self, id: i64) -> anyhow::Result<bool> {\n        let rows_affected = sqlx::query!(\n            r#\"\nUPDATE todos\nSET done = TRUE\nWHERE id = $1\n        \"#,\n            id\n        )\n        .execute(&*self.pg_pool)\n        .await?\n        .rows_affected();\n\n        Ok(rows_affected > 0)\n    }\n\n    async fn list_todos(&self) -> anyhow::Result<()> {\n        let recs = sqlx::query!(\n            r#\"\nSELECT id, description, done\nFROM todos\nORDER BY id\n        \"#\n        )\n        .fetch_all(&*self.pg_pool)\n        .await?;\n\n        for rec in recs {\n            println!(\n                \"- [{}] {}: {}\",\n                if rec.done { \"x\" } else { \" \" },\n                rec.id,\n                &rec.description,\n            );\n        }\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use mockall::predicate::*;\n\n    #[async_std::test]\n    async fn test_mocked_add() {\n        let description = String::from(\"My todo\");\n        let args = Args {\n            cmd: Some(Command::Add {\n                description: description.clone(),\n            }),\n        };\n\n        let mut todo_repo = MockTodoRepo::new();\n        todo_repo\n            .expect_add_todo()\n            .times(1)\n            .with(eq(description))\n            .returning(|_| Ok(1));\n\n        let mut writer = Vec::new();\n\n        handle_command(args, todo_repo, &mut writer).await.unwrap();\n\n        assert_eq!(\n            String::from_utf8_lossy(&writer),\n            \"Adding new todo with description \\'My todo\\'\\nAdded new todo with id 1\\n\"\n        );\n    }\n}\n"
  },
  {
    "path": "examples/postgres/multi-database/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-multi-database\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nrepository.workspace = true\nkeywords.workspace = true\ncategories.workspace = true\nauthors.workspace = true\n\n[dependencies]\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n\ncolor-eyre = \"0.6.3\"\ndotenvy = \"0.15.7\"\ntracing-subscriber = \"0.3.19\"\n\nrust_decimal = \"1.36.0\"\n\nrand = \"0.8.5\"\n\n[dependencies.sqlx]\n# version = \"0.9.0\"\nworkspace = true\nfeatures = [\"runtime-tokio\", \"postgres\", \"migrate\", \"sqlx-toml\"]\n\n[dependencies.accounts]\npath = \"accounts\"\npackage = \"sqlx-example-postgres-multi-database-accounts\"\n\n[dependencies.payments]\npath = \"payments\"\npackage = \"sqlx-example-postgres-multi-database-payments\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/postgres/multi-database/README.md",
    "content": "# Using Multiple Databases with `sqlx.toml`\n\nThis example project involves three crates, each owning a different schema in one database,\nwith their own set of migrations.\n\n* The main crate, a simple binary simulating the action of a REST API.\n    * Owns the `public` schema (tables are referenced unqualified).\n    * Migrations are moved to `src/migrations` using config key `migrate.migrations-dir`\n      to visually separate them from the subcrate folders.\n* `accounts`: a subcrate simulating a reusable account-management crate.\n    * Owns schema `accounts`.\n* `payments`: a subcrate simulating a wrapper for a payments API.\n    * Owns schema `payments`.\n\n## Note: Schema-Qualified Names\n\nThis example uses schema-qualified names everywhere for clarity.\n\nIt can be tempting to change the `search_path` of the connection (MySQL, Postgres) to eliminate the need for schema\nprefixes, but this can cause some really confusing issues when names conflict.\n\nThis example will generate a `_sqlx_migrations` table in three different schemas; if `search_path` is set\nto `public,accounts,payments` and the migrator for the main application attempts to reference the table unqualified,\nit would throw an error.\n\n# Setup\n\nThis example requires running three different sets of migrations.\n\nEnsure `sqlx-cli` is installed with Postgres and `sqlx.toml` support:\n\n```\ncargo install sqlx-cli --features postgres,sqlx-toml\n```\n\nStart a Postgres server (shown here using Docker, `run` command also works with `podman`):\n\n```\ndocker run -d -e POSTGRES_PASSWORD=password -p 5432:5432 --name postgres postgres:latest\n```\n\nCreate `.env` with the various database URLs or set them in your shell environment;\n\n```\nDATABASE_URL=postgres://postgres:password@localhost/example-multi-database\nACCOUNTS_DATABASE_URL=postgres://postgres:password@localhost/example-multi-database-accounts\nPAYMENTS_DATABASE_URL=postgres://postgres:password@localhost/example-multi-database-payments\n```\n\nRun the following commands:\n\n```\n(cd accounts && sqlx db setup)\n(cd payments && sqlx db setup)\nsqlx db setup\n```\n\nIt is an open question how to make this more convenient; `sqlx-cli` could gain a `--recursive` flag that checks\nsubdirectories for `sqlx.toml` files, but that would only work for crates within the same workspace. If the `accounts`\nand `payments` crates were instead crates.io dependencies, we would need Cargo's help to resolve that information.\n\nAn issue has been opened for discussion: <https://github.com/launchbadge/sqlx/issues/3761>\n"
  },
  {
    "path": "examples/postgres/multi-database/accounts/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-multi-database-accounts\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\nsqlx = { workspace = true, features = [\"postgres\", \"time\", \"uuid\", \"macros\", \"sqlx-toml\"] }\ntokio = { version = \"1\", features = [\"rt\", \"sync\"] }\n\nargon2 = { version = \"0.5.3\", features = [\"password-hash\"] }\npassword-hash = { version = \"0.5\", features = [\"std\"] }\n\nuuid = { version = \"1\", features = [\"serde\"] }\nthiserror = \"1\"\nrand = \"0.8\"\n\ntime = { version = \"0.3.37\", features = [\"serde\"] }\n\nserde = { version = \"1.0.218\", features = [\"derive\"] }\n\n[dev-dependencies]\nsqlx = { workspace = true, features = [\"runtime-tokio\"] }\n"
  },
  {
    "path": "examples/postgres/multi-database/accounts/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\n    return NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\n    execute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/multi-database/accounts/migrations/02_account.sql",
    "content": "create table account\n(\n    account_id    uuid primary key     default gen_random_uuid(),\n    email         text unique not null,\n    password_hash text        not null,\n    created_at    timestamptz not null default now(),\n    updated_at    timestamptz\n);\n\nselect trigger_updated_at('account');\n"
  },
  {
    "path": "examples/postgres/multi-database/accounts/migrations/03_session.sql",
    "content": "create table session\n(\n    session_token text primary key, -- random alphanumeric string\n    account_id    uuid        not null references account (account_id),\n    created_at    timestamptz not null default now()\n);\n"
  },
  {
    "path": "examples/postgres/multi-database/accounts/sqlx.toml",
    "content": "[common]\ndatabase-url-var = \"ACCOUNTS_DATABASE_URL\"\n\n[macros.table-overrides.'account']\n'account_id' = \"crate::AccountId\"\n'password_hash' = \"sqlx::types::Text<password_hash::PasswordHashString>\"\n\n[macros.table-overrides.'session']\n'session_token' = \"crate::SessionToken\"\n'account_id' = \"crate::AccountId\"\n"
  },
  {
    "path": "examples/postgres/multi-database/accounts/src/lib.rs",
    "content": "use argon2::{password_hash, Argon2, PasswordHasher, PasswordVerifier};\nuse password_hash::PasswordHashString;\nuse rand::distributions::{Alphanumeric, DistString};\nuse sqlx::PgPool;\nuse std::sync::Arc;\nuse uuid::Uuid;\n\nuse sqlx::postgres::{PgConnectOptions, PgPoolOptions};\nuse tokio::sync::Semaphore;\n\n#[derive(sqlx::Type, Copy, Clone, Debug, serde::Deserialize, serde::Serialize)]\n#[sqlx(transparent)]\npub struct AccountId(pub Uuid);\n\n#[derive(sqlx::Type, Clone, Debug, serde::Deserialize, serde::Serialize)]\n#[sqlx(transparent)]\npub struct SessionToken(pub String);\n\npub struct Session {\n    pub account_id: AccountId,\n    pub session_token: SessionToken,\n}\n\n#[derive(Clone)]\npub struct AccountsManager {\n    /// To prevent confusion, each crate manages its own database connection pool.\n    pool: PgPool,\n\n    /// Controls how many blocking tasks are allowed to run concurrently for Argon2 hashing.\n    ///\n    /// ### Motivation\n    /// Tokio blocking tasks are generally not designed for CPU-bound work.\n    ///\n    /// If no threads are idle, Tokio will automatically spawn new ones to handle\n    /// new blocking tasks up to a very high limit--512 by default.\n    ///\n    /// This is because blocking tasks are expected to spend their time *blocked*, e.g. on\n    /// blocking I/O, and thus not consume CPU resources or require a lot of context switching.\n    ///\n    /// This strategy is not the most efficient way to use threads for CPU-bound work, which\n    /// should schedule work to a fixed number of threads to minimize context switching\n    /// and memory usage (each new thread needs significant space allocated for its stack).\n    ///\n    /// We can work around this by using a purpose-designed thread-pool, like Rayon,\n    /// but we still have the problem that those APIs usually are not designed to support `async`,\n    /// so we end up needing blocking tasks anyway, or implementing our own work queue using\n    /// channels. Rayon also does not shut down idle worker threads.\n    ///\n    /// `block_in_place` is not a silver bullet, either, as it simply uses `spawn_blocking`\n    /// internally to take over from the current thread while it is executing blocking work.\n    /// This also prevents futures from being polled concurrently in the current task.\n    ///\n    /// We can lower the limit for blocking threads when creating the runtime, but this risks\n    /// starving other blocking tasks that are being created by the application or the Tokio\n    /// runtime itself\n    /// (which are used for `tokio::fs`, stdio, resolving of hostnames by `ToSocketAddrs`, etc.).\n    ///\n    /// Instead, we can just use a Semaphore to limit how many blocking tasks are spawned at once,\n    /// emulating the behavior of a thread pool like Rayon without needing any additional crates.\n    hashing_semaphore: Arc<Semaphore>,\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum CreateAccountError {\n    #[error(\"error creating account: email in-use\")]\n    EmailInUse,\n    #[error(\"error creating account\")]\n    General(\n        #[source]\n        #[from]\n        GeneralError,\n    ),\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum CreateSessionError {\n    #[error(\"unknown email\")]\n    UnknownEmail,\n    #[error(\"invalid password\")]\n    InvalidPassword,\n    #[error(\"authentication error\")]\n    General(\n        #[source]\n        #[from]\n        GeneralError,\n    ),\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum GeneralError {\n    #[error(\"database error\")]\n    Sqlx(\n        #[source]\n        #[from]\n        sqlx::Error,\n    ),\n    #[error(\"error hashing password\")]\n    PasswordHash(\n        #[source]\n        #[from]\n        password_hash::Error,\n    ),\n    #[error(\"task panicked\")]\n    Task(\n        #[source]\n        #[from]\n        tokio::task::JoinError,\n    ),\n}\n\nimpl AccountsManager {\n    pub async fn setup(\n        opts: PgConnectOptions,\n        max_hashing_threads: usize,\n    ) -> Result<Self, GeneralError> {\n        // This should be configurable by the caller, but for simplicity, it's not.\n        let pool = PgPoolOptions::new()\n            .max_connections(5)\n            .connect_with(opts)\n            .await?;\n\n        sqlx::migrate!()\n            .run(&pool)\n            .await\n            .map_err(sqlx::Error::from)?;\n\n        Ok(AccountsManager {\n            pool,\n            hashing_semaphore: Semaphore::new(max_hashing_threads).into(),\n        })\n    }\n\n    async fn hash_password(&self, password: String) -> Result<PasswordHashString, GeneralError> {\n        let guard = self\n            .hashing_semaphore\n            .clone()\n            .acquire_owned()\n            .await\n            .expect(\"BUG: this semaphore should not be closed\");\n\n        // We transfer ownership to the blocking task and back to ensure Tokio doesn't spawn\n        // excess threads.\n        let (_guard, res) = tokio::task::spawn_blocking(move || {\n            let salt = password_hash::SaltString::generate(rand::thread_rng());\n            (\n                guard,\n                Argon2::default()\n                    .hash_password(password.as_bytes(), &salt)\n                    .map(|hash| hash.serialize()),\n            )\n        })\n        .await?;\n\n        Ok(res?)\n    }\n\n    async fn verify_password(\n        &self,\n        password: String,\n        hash: PasswordHashString,\n    ) -> Result<(), CreateSessionError> {\n        let guard = self\n            .hashing_semaphore\n            .clone()\n            .acquire_owned()\n            .await\n            .expect(\"BUG: this semaphore should not be closed\");\n\n        let (_guard, res) = tokio::task::spawn_blocking(move || {\n            (\n                guard,\n                Argon2::default().verify_password(password.as_bytes(), &hash.password_hash()),\n            )\n        })\n        .await\n        .map_err(GeneralError::from)?;\n\n        if let Err(password_hash::Error::Password) = res {\n            return Err(CreateSessionError::InvalidPassword);\n        }\n\n        res.map_err(GeneralError::from)?;\n\n        Ok(())\n    }\n\n    pub async fn create(\n        &self,\n        email: &str,\n        password: String,\n    ) -> Result<AccountId, CreateAccountError> {\n        // Hash password whether the account exists or not to make it harder\n        // to tell the difference in the timing.\n        let hash = self.hash_password(password).await?;\n\n        // Thanks to `sqlx.toml`, `account_id` maps to `AccountId`\n        sqlx::query_scalar!(\n            // language=PostgreSQL\n            \"insert into account(email, password_hash) \\\n             values ($1, $2) \\\n             returning account_id\",\n            email,\n            hash.as_str(),\n        )\n        .fetch_one(&self.pool)\n        .await\n        .map_err(|e| {\n            if e.as_database_error().and_then(|dbe| dbe.constraint())\n                == Some(\"account_account_id_key\")\n            {\n                CreateAccountError::EmailInUse\n            } else {\n                GeneralError::from(e).into()\n            }\n        })\n    }\n\n    pub async fn create_session(\n        &self,\n        email: &str,\n        password: String,\n    ) -> Result<Session, CreateSessionError> {\n        let mut txn = self.pool.begin().await.map_err(GeneralError::from)?;\n\n        // To save a round-trip to the database, we'll speculatively insert the session token\n        // at the same time as we're looking up the password hash.\n        //\n        // This does nothing until the transaction is actually committed.\n        let session_token = SessionToken::generate();\n\n        // Thanks to `sqlx.toml`:\n        // * `account_id` maps to `AccountId`\n        // * `password_hash` maps to `Text<PasswordHashString>`\n        // * `session_token` maps to `SessionToken`\n        let maybe_account = sqlx::query!(\n            // language=PostgreSQL\n            \"with account as (\n                select account_id, password_hash \\\n                from account \\\n                where email = $1\n            ), session as (\n                insert into session(session_token, account_id)\n                select $2, account_id\n                from account\n            )\n            select account.account_id, account.password_hash from account\",\n            email,\n            session_token.0\n        )\n        .fetch_optional(&mut *txn)\n        .await\n        .map_err(GeneralError::from)?;\n\n        let Some(account) = maybe_account else {\n            // Hash the password whether the account exists or not to hide the difference in timing.\n            self.hash_password(password)\n                .await\n                .map_err(GeneralError::from)?;\n            return Err(CreateSessionError::UnknownEmail);\n        };\n\n        self.verify_password(password, account.password_hash.into_inner())\n            .await?;\n\n        txn.commit().await.map_err(GeneralError::from)?;\n\n        Ok(Session {\n            account_id: account.account_id,\n            session_token,\n        })\n    }\n\n    pub async fn auth_session(\n        &self,\n        session_token: &str,\n    ) -> Result<Option<AccountId>, GeneralError> {\n        sqlx::query_scalar!(\n            \"select account_id from session where session_token = $1\",\n            session_token\n        )\n        .fetch_optional(&self.pool)\n        .await\n        .map_err(GeneralError::from)\n    }\n}\n\nimpl SessionToken {\n    const LEN: usize = 32;\n\n    fn generate() -> Self {\n        SessionToken(Alphanumeric.sample_string(&mut rand::thread_rng(), Self::LEN))\n    }\n}\n"
  },
  {
    "path": "examples/postgres/multi-database/payments/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-multi-database-payments\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n\nsqlx = { workspace = true, features = [\"postgres\", \"time\", \"uuid\", \"rust_decimal\", \"sqlx-toml\"] }\n\nrust_decimal = \"1.36.0\"\n\ntime = \"0.3.37\"\nuuid = \"1.12.1\"\n\n[dependencies.accounts]\npath = \"../accounts\"\npackage = \"sqlx-example-postgres-multi-database-accounts\"\n\n[dev-dependencies]\nsqlx = { workspace = true, features = [\"runtime-tokio\"] }\n"
  },
  {
    "path": "examples/postgres/multi-database/payments/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\nreturn NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\nexecute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/multi-database/payments/migrations/02_payment.sql",
    "content": "-- `payments::PaymentStatus`\n--\n-- Historically at LaunchBadge we preferred not to define enums on the database side because it can be annoying\n-- and error-prone to keep them in-sync with the application.\n-- Instead, we let the application define the enum and just have the database store a compact representation of it.\n-- This is mostly a matter of taste, however.\n--\n-- For the purposes of this example, we're using an in-database enum because this is a common use-case\n-- for needing type overrides.\ncreate type payment_status as enum (\n    'pending',\n    'created',\n    'success',\n    'failed'\n    );\n\ncreate table payment\n(\n    payment_id          uuid primary key                 default gen_random_uuid(),\n    -- Since `account` is in a separate database, we can't foreign-key to it.\n    account_id          uuid                    not null,\n\n    status              payment_status not null,\n\n    -- ISO 4217 currency code (https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes)\n    --\n    -- This *could* be an ENUM of currency codes, but constraining this to a set of known values in the database\n    -- would be annoying to keep up to date as support for more currencies is added.\n    --\n    -- Consider also if support for cryptocurrencies is desired; those are not covered by ISO 4217.\n    --\n    -- Though ISO 4217 is a three-character code, `TEXT`, `VARCHAR` and `CHAR(N)`\n    -- all use the same storage format in Postgres. Any constraint against the length of this field\n    -- would purely be a sanity check.\n    currency            text                    not null,\n    -- There's an endless debate about what type should be used to represent currency amounts.\n    --\n    -- Postgres has the `MONEY` type, but the fractional precision depends on a C locale setting and the type is mostly\n    -- optimized for storing USD, or other currencies with a minimum fraction of 1 cent.\n    --\n    -- NEVER use `FLOAT` or `DOUBLE`. IEEE-754 rounding point has round-off and precision errors that make it wholly\n    -- unsuitable for representing real money amounts.\n    --\n    -- `NUMERIC`, being an arbitrary-precision decimal format, is a safe default choice that can support any currency,\n    -- and so is what we've chosen here.\n    amount              NUMERIC                 not null,\n\n    -- Payments almost always take place through a third-party vendor (e.g. PayPal, Stripe, etc.),\n    -- so imagine this is an identifier string for this payment in such a vendor's systems.\n    --\n    -- For privacy and security reasons, payment and personally-identifying information\n    -- (e.g. credit card numbers, bank account numbers, billing addresses) should only be stored with the vendor\n    -- unless there is a good reason otherwise.\n    external_payment_id text,\n    created_at          timestamptz             not null default now(),\n    updated_at          timestamptz\n);\n\nselect trigger_updated_at('payment');\n"
  },
  {
    "path": "examples/postgres/multi-database/payments/sqlx.toml",
    "content": "[common]\ndatabase-url-var = \"PAYMENTS_DATABASE_URL\"\n\n[macros.table-overrides.'payment']\n'payment_id' = \"crate::PaymentId\"\n'account_id' = \"accounts::AccountId\"\n\n[macros.type-overrides]\n'payment_status' = \"crate::PaymentStatus\"\n"
  },
  {
    "path": "examples/postgres/multi-database/payments/src/lib.rs",
    "content": "use accounts::{AccountId, AccountsManager};\nuse sqlx::postgres::{PgConnectOptions, PgPoolOptions};\nuse sqlx::{Acquire, PgConnection, PgPool, Postgres};\nuse time::OffsetDateTime;\nuse uuid::Uuid;\n\n#[derive(sqlx::Type, Copy, Clone, Debug)]\n#[sqlx(transparent)]\npub struct PaymentId(pub Uuid);\n\n#[derive(sqlx::Type, Copy, Clone, Debug)]\n#[sqlx(type_name = \"payment_status\")]\n#[sqlx(rename_all = \"snake_case\")]\npub enum PaymentStatus {\n    Pending,\n    Created,\n    Success,\n    Failed,\n}\n\n// Users often assume that they need `#[derive(FromRow)]` to use `query_as!()`,\n// then are surprised when the derive's control attributes have no effect.\n// The macros currently do *not* use the `FromRow` trait at all.\n// Support for `FromRow` is planned, but would require significant changes to the macros.\n// See https://github.com/launchbadge/sqlx/issues/514 for details.\n#[derive(Clone, Debug)]\npub struct Payment {\n    pub payment_id: PaymentId,\n    pub account_id: AccountId,\n    pub status: PaymentStatus,\n    pub currency: String,\n    // `rust_decimal::Decimal` has more than enough precision for any real-world amount of money.\n    pub amount: rust_decimal::Decimal,\n    pub external_payment_id: Option<String>,\n    pub created_at: OffsetDateTime,\n    pub updated_at: Option<OffsetDateTime>,\n}\n\npub struct PaymentsManager {\n    pool: PgPool,\n}\n\nimpl PaymentsManager {\n    pub async fn setup(opts: PgConnectOptions) -> sqlx::Result<Self> {\n        let pool = PgPoolOptions::new()\n            .max_connections(5)\n            .connect_with(opts)\n            .await?;\n\n        sqlx::migrate!().run(&pool).await?;\n\n        Ok(Self { pool })\n    }\n\n    /// # Note\n    /// For simplicity, this does not ensure that `account_id` actually exists.\n    pub async fn create(\n        &self,\n        account_id: AccountId,\n        currency: &str,\n        amount: rust_decimal::Decimal,\n    ) -> sqlx::Result<Payment> {\n        // Check-out a connection to avoid paying the overhead of acquiring one for each call.\n        let mut conn = self.pool.acquire().await?;\n\n        // Imagine this method does more than just create a record in the database;\n        // maybe it actually initiates the payment with a third-party vendor, like Stripe.\n        //\n        // We need to ensure that we can link the payment in the vendor's systems back to a record\n        // in ours, even if any of the following happens:\n        // * The application dies before storing the external payment ID in the database\n        // * We lose the connection to the database while trying to commit a transaction\n        // * The database server dies while committing the transaction\n        //\n        // Thus, we create the payment in three atomic phases:\n        // * We create the payment record in our system and commit it.\n        // * We create the payment in the vendor's system with our payment ID attached.\n        // * We update our payment record with the vendor's payment ID.\n        let payment_id = sqlx::query_scalar!(\n            \"insert into payment(account_id, status, currency, amount) \\\n             values ($1, $2, $3, $4) \\\n             returning payment_id\",\n            // The database doesn't give us enough information to correctly typecheck `AccountId` here.\n            // We have to insert the UUID directly.\n            account_id.0,\n            PaymentStatus::Pending,\n            currency,\n            amount,\n        )\n        .fetch_one(&mut *conn)\n        .await?;\n\n        // We then create the record with the payment vendor...\n        let external_payment_id = \"foobar1234\";\n\n        // Then we store the external payment ID and update the payment status.\n        //\n        // NOTE: use caution with `select *` or `returning *`;\n        // the order of columns gets baked into the binary, so if it changes between compile time and\n        // run-time, you may run into errors.\n        let payment = sqlx::query_as!(\n            Payment,\n            \"update payment \\\n         set status = $1, external_payment_id = $2 \\\n         where payment_id = $3 \\\n         returning *\",\n            PaymentStatus::Created,\n            external_payment_id,\n            payment_id.0,\n        )\n        .fetch_one(&mut *conn)\n        .await?;\n\n        Ok(payment)\n    }\n\n    pub async fn get(&self, payment_id: PaymentId) -> sqlx::Result<Option<Payment>> {\n        sqlx::query_as!(\n            Payment,\n            // see note above about `select *`\n            \"select * from payment where payment_id = $1\",\n            payment_id.0\n        )\n        .fetch_optional(&self.pool)\n        .await\n    }\n}\n"
  },
  {
    "path": "examples/postgres/multi-database/sqlx.toml",
    "content": "[migrate]\n# Move `migrations/` to under `src/` to separate it from subcrates.\nmigrations-dir = \"src/migrations\""
  },
  {
    "path": "examples/postgres/multi-database/src/main.rs",
    "content": "use accounts::AccountsManager;\nuse color_eyre::eyre;\nuse color_eyre::eyre::{Context, OptionExt};\nuse payments::PaymentsManager;\nuse rand::distributions::{Alphanumeric, DistString};\nuse sqlx::Connection;\n\n#[tokio::main]\nasync fn main() -> eyre::Result<()> {\n    color_eyre::install()?;\n    let _ = dotenvy::dotenv();\n    tracing_subscriber::fmt::init();\n\n    let mut conn = sqlx::PgConnection::connect(\n        // `env::var()` doesn't include the variable name in the error.\n        &dotenvy::var(\"DATABASE_URL\").wrap_err(\"DATABASE_URL must be set\")?,\n    )\n    .await\n    .wrap_err(\"could not connect to database\")?;\n\n    let accounts = AccountsManager::setup(\n        dotenvy::var(\"ACCOUNTS_DATABASE_URL\")\n            .wrap_err(\"ACCOUNTS_DATABASE_URL must be set\")?\n            .parse()\n            .wrap_err(\"error parsing ACCOUNTS_DATABASE_URL\")?,\n        1,\n    )\n    .await\n    .wrap_err(\"error initializing AccountsManager\")?;\n\n    let payments = PaymentsManager::setup(\n        dotenvy::var(\"PAYMENTS_DATABASE_URL\")\n            .wrap_err(\"PAYMENTS_DATABASE_URL must be set\")?\n            .parse()\n            .wrap_err(\"error parsing PAYMENTS_DATABASE_URL\")?,\n    )\n    .await\n    .wrap_err(\"error initializing PaymentsManager\")?;\n\n    // For simplicity's sake, imagine each of these might be invoked by different request routes\n    // in a web application.\n\n    // POST /account\n    let user_email = format!(\"user{}@example.com\", rand::random::<u32>());\n    let user_password = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);\n\n    // Requires an externally managed transaction in case any application-specific records\n    // should be created after the actual account record.\n    let mut txn = conn.begin().await?;\n\n    let account_id = accounts\n        // Takes ownership of the password string because it's sent to another thread for hashing.\n        .create(&user_email, user_password.clone())\n        .await\n        .wrap_err(\"error creating account\")?;\n\n    txn.commit().await?;\n\n    println!(\n        \"created account ID: {}, email: {user_email:?}, password: {user_password:?}\",\n        account_id.0\n    );\n\n    // POST /session\n    // Log the user in.\n    let session = accounts\n        .create_session(&user_email, user_password.clone())\n        .await\n        .wrap_err(\"error creating session\")?;\n\n    // After this, session.session_token should then be returned to the client,\n    // either in the response body or a `Set-Cookie` header.\n    println!(\"created session token: {}\", session.session_token.0);\n\n    // POST /purchase\n    // The client would then pass the session token to authenticated routes.\n    // In this route, they're making some kind of purchase.\n\n    // First, we need to ensure the session is valid.\n    // `session.session_token` would be passed by the client in whatever way is appropriate.\n    //\n    // For a pure REST API, consider an `Authorization: Bearer` header instead of the request body.\n    // With Axum, you can create a reusable extractor that reads the header and validates the session\n    // by implementing `FromRequestParts`.\n    //\n    // For APIs where the browser is intended to be the primary client, using a session cookie\n    // may be easier for the frontend. By setting the cookie with `HttpOnly: true`,\n    // it's impossible for malicious Javascript on the client to access and steal the session token.\n    let account_id = accounts\n        .auth_session(&session.session_token.0)\n        .await\n        .wrap_err(\"error authenticating session\")?\n        .ok_or_eyre(\"session does not exist\")?;\n\n    let purchase_amount: rust_decimal::Decimal = \"12.34\".parse().unwrap();\n\n    // Then, because the user is making a purchase, we record a payment.\n    let payment = payments\n        .create(account_id, \"USD\", purchase_amount)\n        .await\n        .wrap_err(\"error creating payment\")?;\n\n    println!(\"created payment: {payment:?}\");\n\n    let purchase_id = sqlx::query_scalar!(\n        \"insert into purchase(account_id, payment_id, amount) values ($1, $2, $3) returning purchase_id\",\n        account_id.0,\n        payment.payment_id.0,\n        purchase_amount\n    )\n    .fetch_one(&mut conn)\n    .await\n    .wrap_err(\"error creating purchase\")?;\n\n    println!(\"created purchase: {purchase_id}\");\n\n    conn.close().await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/multi-database/src/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\n    return NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\n    execute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/multi-database/src/migrations/02_purchase.sql",
    "content": "create table purchase\n(\n    purchase_id uuid primary key     default gen_random_uuid(),\n    account_id  uuid        not null,\n    payment_id  uuid        not null,\n    amount      numeric     not null,\n    created_at  timestamptz not null default now(),\n    updated_at  timestamptz\n);\n\nselect trigger_updated_at('purchase');\n"
  },
  {
    "path": "examples/postgres/multi-tenant/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-multi-tenant\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nrepository.workspace = true\nkeywords.workspace = true\ncategories.workspace = true\nauthors.workspace = true\n\n[dependencies]\ntokio = { version = \"1\", features = [\"rt-multi-thread\", \"macros\"] }\n\ncolor-eyre = \"0.6.3\"\ndotenvy = \"0.15.7\"\ntracing-subscriber = \"0.3.19\"\n\nrust_decimal = \"1.36.0\"\n\nrand = \"0.8.5\"\n\n[dependencies.sqlx]\n# version = \"0.9.0\"\nworkspace = true\nfeatures = [\"runtime-tokio\", \"postgres\", \"migrate\", \"sqlx-toml\"]\n\n[dependencies.accounts]\npath = \"accounts\"\npackage = \"sqlx-example-postgres-multi-tenant-accounts\"\n\n[dependencies.payments]\npath = \"payments\"\npackage = \"sqlx-example-postgres-multi-tenant-payments\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/postgres/multi-tenant/README.md",
    "content": "# Multi-tenant Databases with `sqlx.toml`\n\nThis example project involves three crates, each owning a different schema in one database,\nwith their own set of migrations.\n\n* The main crate, a simple binary simulating the action of a REST API.\n    * Owns the `public` schema (tables are referenced unqualified).\n    * Migrations are moved to `src/migrations` using config key `migrate.migrations-dir`\n      to visually separate them from the subcrate folders.\n* `accounts`: a subcrate simulating a reusable account-management crate.\n    * Owns schema `accounts`.\n* `payments`: a subcrate simulating a wrapper for a payments API.\n    * Owns schema `payments`.\n\n## Note: Schema-Qualified Names\n\nThis example uses schema-qualified names everywhere for clarity.\n\nIt can be tempting to change the `search_path` of the connection (MySQL, Postgres) to eliminate the need for schema\nprefixes, but this can cause some really confusing issues when names conflict.\n\nThis example will generate a `_sqlx_migrations` table in three different schemas; if `search_path` is set\nto `public,accounts,payments` and the migrator for the main application attempts to reference the table unqualified,\nit would throw an error.\n\n# Setup\n\nThis example requires running three different sets of migrations.\n\nEnsure `sqlx-cli` is installed with Postgres and `sqlx.toml` support:\n\n```\ncargo install sqlx-cli --features postgres,sqlx-toml\n```\n\nStart a Postgres server (shown here using Docker, `run` command also works with `podman`):\n\n```\ndocker run -d -e POSTGRES_PASSWORD=password -p 5432:5432 --name postgres postgres:latest\n```\n\nCreate `.env` with `DATABASE_URL` or set the variable in your shell environment;\n\n```\nDATABASE_URL=postgres://postgres:password@localhost/example-multi-tenant\n```\n\nRun the following commands:\n\n```\n(cd accounts && sqlx db setup)\n(cd payments && sqlx migrate run)\nsqlx migrate run\n```\n\nIt is an open question how to make this more convenient; `sqlx-cli` could gain a `--recursive` flag that checks\nsubdirectories for `sqlx.toml` files, but that would only work for crates within the same workspace. If the `accounts`\nand `payments` crates were instead crates.io dependencies, we would need Cargo's help to resolve that information.\n\nAn issue has been opened for discussion: <https://github.com/launchbadge/sqlx/issues/3761>\n"
  },
  {
    "path": "examples/postgres/multi-tenant/accounts/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-multi-tenant-accounts\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\ntokio = { version = \"1\", features = [\"rt\", \"sync\"] }\n\nargon2 = { version = \"0.5.3\", features = [\"password-hash\"] }\npassword-hash = { version = \"0.5\", features = [\"std\"] }\n\nuuid = { version = \"1\", features = [\"serde\"] }\nthiserror = \"1\"\nrand = \"0.8\"\n\ntime = { version = \"0.3.37\", features = [\"serde\"] }\n\nserde = { version = \"1.0.218\", features = [\"derive\"] }\n\n[dependencies.sqlx]\n# version = \"0.9.0\"\nworkspace = true\nfeatures = [\"postgres\", \"time\", \"uuid\", \"macros\", \"sqlx-toml\", \"migrate\"]\n\n[dev-dependencies]\nsqlx = { workspace = true, features = [\"runtime-tokio\"] }\n"
  },
  {
    "path": "examples/postgres/multi-tenant/accounts/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select accounts.trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function accounts.set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\n    return NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function accounts.trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\n    execute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION accounts.set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/multi-tenant/accounts/migrations/02_account.sql",
    "content": "create table accounts.account\n(\n    account_id    uuid primary key     default gen_random_uuid(),\n    email         text unique not null,\n    password_hash text        not null,\n    created_at    timestamptz not null default now(),\n    updated_at    timestamptz\n);\n\nselect accounts.trigger_updated_at('accounts.account');\n"
  },
  {
    "path": "examples/postgres/multi-tenant/accounts/migrations/03_session.sql",
    "content": "create table accounts.session\n(\n    session_token text primary key, -- random alphanumeric string\n    account_id    uuid        not null references accounts.account (account_id),\n    created_at    timestamptz not null default now()\n);\n"
  },
  {
    "path": "examples/postgres/multi-tenant/accounts/sqlx.toml",
    "content": "[migrate]\ncreate-schemas = [\"accounts\"]\ntable-name = \"accounts._sqlx_migrations\"\n\n[macros.table-overrides.'accounts.account']\n'account_id' = \"crate::AccountId\"\n'password_hash' = \"sqlx::types::Text<password_hash::PasswordHashString>\"\n\n[macros.table-overrides.'accounts.session']\n'session_token' = \"crate::SessionToken\"\n'account_id' = \"crate::AccountId\"\n"
  },
  {
    "path": "examples/postgres/multi-tenant/accounts/src/lib.rs",
    "content": "use argon2::{password_hash, Argon2, PasswordHasher, PasswordVerifier};\nuse password_hash::PasswordHashString;\nuse rand::distributions::{Alphanumeric, DistString};\nuse sqlx::{Acquire, Executor, PgTransaction, Postgres};\nuse std::sync::Arc;\nuse uuid::Uuid;\n\nuse tokio::sync::Semaphore;\n\n#[derive(sqlx::Type, Copy, Clone, Debug, serde::Deserialize, serde::Serialize)]\n#[sqlx(transparent)]\npub struct AccountId(pub Uuid);\n\n#[derive(sqlx::Type, Clone, Debug, serde::Deserialize, serde::Serialize)]\n#[sqlx(transparent)]\npub struct SessionToken(pub String);\n\npub struct Session {\n    pub account_id: AccountId,\n    pub session_token: SessionToken,\n}\n\npub struct AccountsManager {\n    /// Controls how many blocking tasks are allowed to run concurrently for Argon2 hashing.\n    ///\n    /// ### Motivation\n    /// Tokio blocking tasks are generally not designed for CPU-bound work.\n    ///\n    /// If no threads are idle, Tokio will automatically spawn new ones to handle\n    /// new blocking tasks up to a very high limit--512 by default.\n    ///\n    /// This is because blocking tasks are expected to spend their time *blocked*, e.g. on\n    /// blocking I/O, and thus not consume CPU resources or require a lot of context switching.\n    ///\n    /// This strategy is not the most efficient way to use threads for CPU-bound work, which\n    /// should schedule work to a fixed number of threads to minimize context switching\n    /// and memory usage (each new thread needs significant space allocated for its stack).\n    ///\n    /// We can work around this by using a purpose-designed thread-pool, like Rayon,\n    /// but we still have the problem that those APIs usually are not designed to support `async`,\n    /// so we end up needing blocking tasks anyway, or implementing our own work queue using\n    /// channels. Rayon also does not shut down idle worker threads.\n    ///\n    /// `block_in_place` is not a silver bullet, either, as it simply uses `spawn_blocking`\n    /// internally to take over from the current thread while it is executing blocking work.\n    /// This also prevents futures from being polled concurrently in the current task.\n    ///\n    /// We can lower the limit for blocking threads when creating the runtime, but this risks\n    /// starving other blocking tasks that are being created by the application or the Tokio\n    /// runtime itself\n    /// (which are used for `tokio::fs`, stdio, resolving of hostnames by `ToSocketAddrs`, etc.).\n    ///\n    /// Instead, we can just use a Semaphore to limit how many blocking tasks are spawned at once,\n    /// emulating the behavior of a thread pool like Rayon without needing any additional crates.\n    hashing_semaphore: Arc<Semaphore>,\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum CreateAccountError {\n    #[error(\"error creating account: email in-use\")]\n    EmailInUse,\n    #[error(\"error creating account\")]\n    General(\n        #[source]\n        #[from]\n        GeneralError,\n    ),\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum CreateSessionError {\n    #[error(\"unknown email\")]\n    UnknownEmail,\n    #[error(\"invalid password\")]\n    InvalidPassword,\n    #[error(\"authentication error\")]\n    General(\n        #[source]\n        #[from]\n        GeneralError,\n    ),\n}\n\n#[derive(Debug, thiserror::Error)]\npub enum GeneralError {\n    #[error(\"database error\")]\n    Sqlx(\n        #[source]\n        #[from]\n        sqlx::Error,\n    ),\n    #[error(\"error hashing password\")]\n    PasswordHash(\n        #[source]\n        #[from]\n        password_hash::Error,\n    ),\n    #[error(\"task panicked\")]\n    Task(\n        #[source]\n        #[from]\n        tokio::task::JoinError,\n    ),\n}\n\nimpl AccountsManager {\n    pub async fn setup(\n        pool: impl Acquire<'_, Database = Postgres>,\n        max_hashing_threads: usize,\n    ) -> Result<Self, GeneralError> {\n        sqlx::migrate!()\n            .run(pool)\n            .await\n            .map_err(sqlx::Error::from)?;\n\n        Ok(AccountsManager {\n            hashing_semaphore: Semaphore::new(max_hashing_threads).into(),\n        })\n    }\n\n    async fn hash_password(&self, password: String) -> Result<PasswordHashString, GeneralError> {\n        let guard = self\n            .hashing_semaphore\n            .clone()\n            .acquire_owned()\n            .await\n            .expect(\"BUG: this semaphore should not be closed\");\n\n        // We transfer ownership to the blocking task and back to ensure Tokio doesn't spawn\n        // excess threads.\n        let (_guard, res) = tokio::task::spawn_blocking(move || {\n            let salt = password_hash::SaltString::generate(rand::thread_rng());\n            (\n                guard,\n                Argon2::default()\n                    .hash_password(password.as_bytes(), &salt)\n                    .map(|hash| hash.serialize()),\n            )\n        })\n        .await?;\n\n        Ok(res?)\n    }\n\n    async fn verify_password(\n        &self,\n        password: String,\n        hash: PasswordHashString,\n    ) -> Result<(), CreateSessionError> {\n        let guard = self\n            .hashing_semaphore\n            .clone()\n            .acquire_owned()\n            .await\n            .expect(\"BUG: this semaphore should not be closed\");\n\n        let (_guard, res) = tokio::task::spawn_blocking(move || {\n            (\n                guard,\n                Argon2::default().verify_password(password.as_bytes(), &hash.password_hash()),\n            )\n        })\n        .await\n        .map_err(GeneralError::from)?;\n\n        if let Err(password_hash::Error::Password) = res {\n            return Err(CreateSessionError::InvalidPassword);\n        }\n\n        res.map_err(GeneralError::from)?;\n\n        Ok(())\n    }\n\n    pub async fn create(\n        &self,\n        txn: &mut PgTransaction<'_>,\n        email: &str,\n        password: String,\n    ) -> Result<AccountId, CreateAccountError> {\n        // Hash password whether the account exists or not to make it harder\n        // to tell the difference in the timing.\n        let hash = self.hash_password(password).await?;\n\n        // Thanks to `sqlx.toml`, `account_id` maps to `AccountId`\n        sqlx::query_scalar!(\n            // language=PostgreSQL\n            \"insert into accounts.account(email, password_hash) \\\n             values ($1, $2) \\\n             returning account_id\",\n            email,\n            hash.as_str(),\n        )\n        .fetch_one(&mut **txn)\n        .await\n        .map_err(|e| {\n            if e.as_database_error().and_then(|dbe| dbe.constraint())\n                == Some(\"account_account_id_key\")\n            {\n                CreateAccountError::EmailInUse\n            } else {\n                GeneralError::from(e).into()\n            }\n        })\n    }\n\n    pub async fn create_session(\n        &self,\n        db: impl Acquire<'_, Database = Postgres>,\n        email: &str,\n        password: String,\n    ) -> Result<Session, CreateSessionError> {\n        let mut txn = db.begin().await.map_err(GeneralError::from)?;\n\n        // To save a round-trip to the database, we'll speculatively insert the session token\n        // at the same time as we're looking up the password hash.\n        //\n        // This does nothing until the transaction is actually committed.\n        let session_token = SessionToken::generate();\n\n        // Thanks to `sqlx.toml`:\n        // * `account_id` maps to `AccountId`\n        // * `password_hash` maps to `Text<PasswordHashString>`\n        // * `session_token` maps to `SessionToken`\n        let maybe_account = sqlx::query!(\n            // language=PostgreSQL\n            \"with account as (\n                select account_id, password_hash \\\n                from accounts.account \\\n                where email = $1\n            ), session as (\n                insert into accounts.session(session_token, account_id)\n                select $2, account_id\n                from account\n            )\n            select account.account_id, account.password_hash from account\",\n            email,\n            session_token.0\n        )\n        .fetch_optional(&mut *txn)\n        .await\n        .map_err(GeneralError::from)?;\n\n        let Some(account) = maybe_account else {\n            // Hash the password whether the account exists or not to hide the difference in timing.\n            self.hash_password(password)\n                .await\n                .map_err(GeneralError::from)?;\n            return Err(CreateSessionError::UnknownEmail);\n        };\n\n        self.verify_password(password, account.password_hash.into_inner())\n            .await?;\n\n        txn.commit().await.map_err(GeneralError::from)?;\n\n        Ok(Session {\n            account_id: account.account_id,\n            session_token,\n        })\n    }\n\n    pub async fn auth_session(\n        &self,\n        db: impl Executor<'_, Database = Postgres>,\n        session_token: &str,\n    ) -> Result<Option<AccountId>, GeneralError> {\n        sqlx::query_scalar!(\n            \"select account_id from accounts.session where session_token = $1\",\n            session_token\n        )\n        .fetch_optional(db)\n        .await\n        .map_err(GeneralError::from)\n    }\n}\n\nimpl SessionToken {\n    const LEN: usize = 32;\n\n    fn generate() -> Self {\n        SessionToken(Alphanumeric.sample_string(&mut rand::thread_rng(), Self::LEN))\n    }\n}\n"
  },
  {
    "path": "examples/postgres/multi-tenant/payments/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-multi-tenant-payments\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[dependencies]\n\nrust_decimal = \"1.36.0\"\n\ntime = \"0.3.37\"\nuuid = \"1.12.1\"\n\n[dependencies.sqlx]\n# version = \"0.9.0\"\nworkspace = true\nfeatures = [\"postgres\", \"time\", \"uuid\", \"rust_decimal\", \"sqlx-toml\", \"migrate\"]\n\n[dependencies.accounts]\npath = \"../accounts\"\npackage = \"sqlx-example-postgres-multi-tenant-accounts\"\n\n[dev-dependencies]\nsqlx = { workspace = true, features = [\"runtime-tokio\"] }\n"
  },
  {
    "path": "examples/postgres/multi-tenant/payments/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select payments.trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function payments.set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\nreturn NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function payments.trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\nexecute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION payments.set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/multi-tenant/payments/migrations/02_payment.sql",
    "content": "-- `payments::PaymentStatus`\n--\n-- Historically at LaunchBadge we preferred not to define enums on the database side because it can be annoying\n-- and error-prone to keep them in-sync with the application.\n-- Instead, we let the application define the enum and just have the database store a compact representation of it.\n-- This is mostly a matter of taste, however.\n--\n-- For the purposes of this example, we're using an in-database enum because this is a common use-case\n-- for needing type overrides.\ncreate type payments.payment_status as enum (\n    'pending',\n    'created',\n    'success',\n    'failed'\n    );\n\ncreate table payments.payment\n(\n    payment_id          uuid primary key                 default gen_random_uuid(),\n    -- This cross-schema reference means migrations for the `accounts` crate should be run first.\n    account_id          uuid                    not null references accounts.account (account_id),\n\n    status              payments.payment_status not null,\n\n    -- ISO 4217 currency code (https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes)\n    --\n    -- This *could* be an ENUM of currency codes, but constraining this to a set of known values in the database\n    -- would be annoying to keep up to date as support for more currencies is added.\n    --\n    -- Consider also if support for cryptocurrencies is desired; those are not covered by ISO 4217.\n    --\n    -- Though ISO 4217 is a three-character code, `TEXT`, `VARCHAR` and `CHAR(N)`\n    -- all use the same storage format in Postgres. Any constraint against the length of this field\n    -- would purely be a sanity check.\n    currency            text                    not null,\n    -- There's an endless debate about what type should be used to represent currency amounts.\n    --\n    -- Postgres has the `MONEY` type, but the fractional precision depends on a C locale setting and the type is mostly\n    -- optimized for storing USD, or other currencies with a minimum fraction of 1 cent.\n    --\n    -- NEVER use `FLOAT` or `DOUBLE`. IEEE-754 rounding point has round-off and precision errors that make it wholly\n    -- unsuitable for representing real money amounts.\n    --\n    -- `NUMERIC`, being an arbitrary-precision decimal format, is a safe default choice that can support any currency,\n    -- and so is what we've chosen here.\n    amount              NUMERIC                 not null,\n\n    -- Payments almost always take place through a third-party vendor (e.g. PayPal, Stripe, etc.),\n    -- so imagine this is an identifier string for this payment in such a vendor's systems.\n    --\n    -- For privacy and security reasons, payment and personally-identifying information\n    -- (e.g. credit card numbers, bank account numbers, billing addresses) should only be stored with the vendor\n    -- unless there is a good reason otherwise.\n    external_payment_id text,\n    created_at          timestamptz             not null default now(),\n    updated_at          timestamptz\n);\n\nselect payments.trigger_updated_at('payments.payment');\n"
  },
  {
    "path": "examples/postgres/multi-tenant/payments/sqlx.toml",
    "content": "[migrate]\ncreate-schemas = [\"payments\"]\ntable-name = \"payments._sqlx_migrations\"\n\n[macros.table-overrides.'payments.payment']\n'payment_id' = \"crate::PaymentId\"\n'account_id' = \"accounts::AccountId\"\n\n[macros.type-overrides]\n'payments.payment_status' = \"crate::PaymentStatus\"\n"
  },
  {
    "path": "examples/postgres/multi-tenant/payments/src/lib.rs",
    "content": "use accounts::AccountId;\nuse sqlx::{Acquire, PgConnection, Postgres};\nuse time::OffsetDateTime;\nuse uuid::Uuid;\n\n#[derive(sqlx::Type, Copy, Clone, Debug)]\n#[sqlx(transparent)]\npub struct PaymentId(pub Uuid);\n\n#[derive(sqlx::Type, Copy, Clone, Debug)]\n#[sqlx(type_name = \"payments.payment_status\")]\n#[sqlx(rename_all = \"snake_case\")]\npub enum PaymentStatus {\n    Pending,\n    Created,\n    Success,\n    Failed,\n}\n\n// Users often assume that they need `#[derive(FromRow)]` to use `query_as!()`,\n// then are surprised when the derive's control attributes have no effect.\n// The macros currently do *not* use the `FromRow` trait at all.\n// Support for `FromRow` is planned, but would require significant changes to the macros.\n// See https://github.com/launchbadge/sqlx/issues/514 for details.\n#[derive(Clone, Debug)]\npub struct Payment {\n    pub payment_id: PaymentId,\n    pub account_id: AccountId,\n    pub status: PaymentStatus,\n    pub currency: String,\n    // `rust_decimal::Decimal` has more than enough precision for any real-world amount of money.\n    pub amount: rust_decimal::Decimal,\n    pub external_payment_id: Option<String>,\n    pub created_at: OffsetDateTime,\n    pub updated_at: Option<OffsetDateTime>,\n}\n\n// Accepting `impl Acquire` allows this function to be generic over `Pool`, `Connection` and `Transaction`.\npub async fn migrate(db: impl Acquire<'_, Database = Postgres>) -> sqlx::Result<()> {\n    sqlx::migrate!().run(db).await?;\n    Ok(())\n}\n\npub async fn create(\n    conn: &mut PgConnection,\n    account_id: AccountId,\n    currency: &str,\n    amount: rust_decimal::Decimal,\n) -> sqlx::Result<Payment> {\n    // Imagine this method does more than just create a record in the database;\n    // maybe it actually initiates the payment with a third-party vendor, like Stripe.\n    //\n    // We need to ensure that we can link the payment in the vendor's systems back to a record\n    // in ours, even if any of the following happens:\n    // * The application dies before storing the external payment ID in the database\n    // * We lose the connection to the database while trying to commit a transaction\n    // * The database server dies while committing the transaction\n    //\n    // Thus, we create the payment in three atomic phases:\n    // * We create the payment record in our system and commit it.\n    // * We create the payment in the vendor's system with our payment ID attached.\n    // * We update our payment record with the vendor's payment ID.\n    let payment_id = sqlx::query_scalar!(\n        \"insert into payments.payment(account_id, status, currency, amount) \\\n         values ($1, $2, $3, $4) \\\n         returning payment_id\",\n        // The database doesn't give us enough information to correctly typecheck `AccountId` here.\n        // We have to insert the UUID directly.\n        account_id.0,\n        PaymentStatus::Pending,\n        currency,\n        amount,\n    )\n    .fetch_one(&mut *conn)\n    .await?;\n\n    // We then create the record with the payment vendor...\n    let external_payment_id = \"foobar1234\";\n\n    // Then we store the external payment ID and update the payment status.\n    //\n    // NOTE: use caution with `select *` or `returning *`;\n    // the order of columns gets baked into the binary, so if it changes between compile time and\n    // run-time, you may run into errors.\n    let payment = sqlx::query_as!(\n        Payment,\n        \"update payments.payment \\\n         set status = $1, external_payment_id = $2 \\\n         where payment_id = $3 \\\n         returning *\",\n        PaymentStatus::Created,\n        external_payment_id,\n        payment_id.0,\n    )\n    .fetch_one(&mut *conn)\n    .await?;\n\n    Ok(payment)\n}\n\npub async fn get(db: &mut PgConnection, payment_id: PaymentId) -> sqlx::Result<Option<Payment>> {\n    sqlx::query_as!(\n        Payment,\n        // see note above about `select *`\n        \"select * from payments.payment where payment_id = $1\",\n        payment_id.0\n    )\n    .fetch_optional(db)\n    .await\n}\n"
  },
  {
    "path": "examples/postgres/multi-tenant/sqlx.toml",
    "content": "[migrate]\n# Move `migrations/` to under `src/` to separate it from subcrates.\nmigrations-dir = \"src/migrations\""
  },
  {
    "path": "examples/postgres/multi-tenant/src/main.rs",
    "content": "use accounts::AccountsManager;\nuse color_eyre::eyre;\nuse color_eyre::eyre::{Context, OptionExt};\nuse rand::distributions::{Alphanumeric, DistString};\nuse sqlx::Connection;\n\n#[tokio::main]\nasync fn main() -> eyre::Result<()> {\n    color_eyre::install()?;\n    let _ = dotenvy::dotenv();\n    tracing_subscriber::fmt::init();\n\n    let mut conn = sqlx::PgConnection::connect(\n        // `env::var()` doesn't include the variable name in the error.\n        &dotenvy::var(\"DATABASE_URL\").wrap_err(\"DATABASE_URL must be set\")?,\n    )\n    .await\n    .wrap_err(\"could not connect to database\")?;\n\n    // Runs migration for `accounts` internally.\n    let accounts = AccountsManager::setup(&mut conn, 1)\n        .await\n        .wrap_err(\"error initializing AccountsManager\")?;\n\n    payments::migrate(&mut conn)\n        .await\n        .wrap_err(\"error running payments migrations\")?;\n\n    // For simplicity's sake, imagine each of these might be invoked by different request routes\n    // in a web application.\n\n    // POST /account\n    let user_email = format!(\"user{}@example.com\", rand::random::<u32>());\n    let user_password = Alphanumeric.sample_string(&mut rand::thread_rng(), 16);\n\n    // Requires an externally managed transaction in case any application-specific records\n    // should be created after the actual account record.\n    let mut txn = conn.begin().await?;\n\n    let account_id = accounts\n        // Takes ownership of the password string because it's sent to another thread for hashing.\n        .create(&mut txn, &user_email, user_password.clone())\n        .await\n        .wrap_err(\"error creating account\")?;\n\n    txn.commit().await?;\n\n    println!(\n        \"created account ID: {}, email: {user_email:?}, password: {user_password:?}\",\n        account_id.0\n    );\n\n    // POST /session\n    // Log the user in.\n    let session = accounts\n        .create_session(&mut conn, &user_email, user_password.clone())\n        .await\n        .wrap_err(\"error creating session\")?;\n\n    // After this, session.session_token should then be returned to the client,\n    // either in the response body or a `Set-Cookie` header.\n    println!(\"created session token: {}\", session.session_token.0);\n\n    // POST /purchase\n    // The client would then pass the session token to authenticated routes.\n    // In this route, they're making some kind of purchase.\n\n    // First, we need to ensure the session is valid.\n    // `session.session_token` would be passed by the client in whatever way is appropriate.\n    //\n    // For a pure REST API, consider an `Authorization: Bearer` header instead of the request body.\n    // With Axum, you can create a reusable extractor that reads the header and validates the session\n    // by implementing `FromRequestParts`.\n    //\n    // For APIs where the browser is intended to be the primary client, using a session cookie\n    // may be easier for the frontend. By setting the cookie with `HttpOnly: true`,\n    // it's impossible for malicious Javascript on the client to access and steal the session token.\n    let account_id = accounts\n        .auth_session(&mut conn, &session.session_token.0)\n        .await\n        .wrap_err(\"error authenticating session\")?\n        .ok_or_eyre(\"session does not exist\")?;\n\n    let purchase_amount: rust_decimal::Decimal = \"12.34\".parse().unwrap();\n\n    // Then, because the user is making a purchase, we record a payment.\n    let payment = payments::create(&mut conn, account_id, \"USD\", purchase_amount)\n        .await\n        .wrap_err(\"error creating payment\")?;\n\n    println!(\"created payment: {payment:?}\");\n\n    let purchase_id = sqlx::query_scalar!(\n        \"insert into purchase(account_id, payment_id, amount) values ($1, $2, $3) returning purchase_id\",\n        account_id.0,\n        payment.payment_id.0,\n        purchase_amount\n    )\n    .fetch_one(&mut conn)\n    .await\n    .wrap_err(\"error creating purchase\")?;\n\n    println!(\"created purchase: {purchase_id}\");\n\n    conn.close().await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/multi-tenant/src/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\n    return NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\n    execute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/multi-tenant/src/migrations/02_purchase.sql",
    "content": "create table purchase\n(\n    purchase_id uuid primary key     default gen_random_uuid(),\n    account_id  uuid        not null references accounts.account (account_id),\n    payment_id  uuid        not null references payments.payment (payment_id),\n    amount      numeric     not null,\n    created_at  timestamptz not null default now(),\n    updated_at  timestamptz\n);\n\nselect trigger_updated_at('purchase');\n"
  },
  {
    "path": "examples/postgres/preferred-crates/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-preferred-crates\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nrepository.workspace = true\nkeywords.workspace = true\ncategories.workspace = true\nauthors.workspace = true\n\n[dependencies]\ndotenvy.workspace = true\n\nanyhow = \"1\"\nchrono = \"0.4\"\nserde = { version = \"1\", features = [\"derive\"] }\nuuid = { version = \"1\", features = [\"serde\"] }\n\n[dependencies.tokio]\nworkspace = true\nfeatures = [\"rt-multi-thread\", \"macros\"]\n\n[dependencies.sqlx]\n# version = \"0.9.0\"\nworkspace = true\nfeatures = [\"runtime-tokio\", \"postgres\", \"bigdecimal\", \"chrono\", \"derive\", \"macros\", \"migrate\", \"sqlx-toml\"]\n\n[dependencies.uses-rust-decimal]\npath = \"uses-rust-decimal\"\npackage = \"sqlx-example-postgres-preferred-crates-uses-rust-decimal\"\n\n[dependencies.uses-time]\npath = \"uses-time\"\npackage = \"sqlx-example-postgres-preferred-crates-uses-time\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/postgres/preferred-crates/README.md",
    "content": "# Usage of `macros.preferred-crates` in `sqlx.toml`\n\n## The Problem\n\nSQLx has many optional features that enable integrations for external crates to map from/to SQL types.\n\nIn some cases, more than one optional feature applies to the same set of types:\n\n* The `chrono` and `time` features enable mapping SQL date/time types to those in these crates.\n* Similarly, `bigdecimal` and `rust_decimal` enable mapping for the SQL `NUMERIC` type.\n\nThroughout its existence, the `query!()` family of macros has inferred which crate to use based on which optional \nfeature was enabled. If multiple features are enabled, one takes precedent over the other: `time` over `chrono`, \n`rust_decimal` over `bigdecimal`, etc. The ordering is purely the result of historical happenstance and \ndoes not indicate any specific preference for one crate over another. They each have their tradeoffs.\n\nThis works fine when only one crate in the dependency graph depends on SQLx, but can break down if another crate\nin the dependency graph also depends on SQLx. Because of Cargo's [feature unification], any features enabled\nby this other crate are also forced on for all other crates that depend on the same version of SQLx in the same project.\n\nThis is intentional design on Cargo's part; features are meant to be purely additive, so it can build each transitive\ndependency just once no matter how many crates depend on it. Otherwise, this could result in combinatorial explosion.\n\nUnfortunately for us, this means that if your project depends on SQLx and enables the `chrono` feature, but also depends \non another crate that enables the `time` feature, the `query!()` macros will end up thinking that _you_ want to use \nthe `time` crate, because they don't know any better. \n\nFixing this has historically required patching the dependency, which is annoying to maintain long-term.\n\n[feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification\n\n## The Solution\n\nHowever, as of 0.9.0, SQLx has gained the ability to configure the macros through the use of a `sqlx.toml` file.\n\nThis includes the ability to tell the macros which crate you prefer, overriding the inference.\n\nSee the [`sqlx.toml`](./sqlx.toml) file in this directory for details.\n\nA full reference `sqlx.toml` is also available as `sqlx-core/src/config/reference.toml`.\n\n## This Example\n\nThis example exists both to showcase the macro configuration and also serve as a test for the functionality.\n\nIt consists of three crates:\n\n* The root crate, which depends on SQLx and enables the `chrono` and `bigdecimal` features,\n* `uses-rust-decimal`, a dependency which also depends on SQLx and enables the `rust_decimal` feature,\n* and `uses-time`, a dependency which also depends on SQLx and enables the `time` feature.\n  * This serves as a stand-in for `tower-sessions-sqlx-store`, which is [one of the culprits for this issue](https://github.com/launchbadge/sqlx/issues/3412#issuecomment-2277377597).\n\nGiven that both dependencies enable features with higher precedence, they would historically have interfered\nwith the usage in the root crate. (Pretend that they're published to crates.io and cannot be easily changed.) \nHowever, because the root crate uses a `sqlx.toml`, the macros know exactly which crates it wants to use and everyone's happy.\n"
  },
  {
    "path": "examples/postgres/preferred-crates/sqlx.toml",
    "content": "[migrate]\n# Move `migrations/` to under `src/` to separate it from subcrates.\nmigrations-dir = \"src/migrations\"\n\n[macros.preferred-crates]\n# Keeps `time` from taking precedent even though it's enabled by a dependency.\ndate-time = \"chrono\"\n# Same thing with `rust_decimal`\nnumeric = \"bigdecimal\"\n"
  },
  {
    "path": "examples/postgres/preferred-crates/src/main.rs",
    "content": "use anyhow::Context;\nuse chrono::{DateTime, Utc};\nuse sqlx::{Connection, PgConnection};\nuse std::time::Duration;\nuse uuid::Uuid;\n\n#[derive(serde::Serialize, serde::Deserialize, PartialEq, Eq, Debug)]\nstruct SessionData {\n    user_id: Uuid,\n}\n\n#[derive(sqlx::FromRow, Debug)]\nstruct User {\n    id: Uuid,\n    username: String,\n    password_hash: String,\n    // Because `time` is enabled by a transitive dependency, we previously would have needed\n    // a type override in the query to get types from `chrono`.\n    created_at: DateTime<Utc>,\n    updated_at: Option<DateTime<Utc>>,\n}\n\nconst SESSION_DURATION: Duration = Duration::from_secs(60 * 60); // 1 hour\n\n#[tokio::main]\nasync fn main() -> anyhow::Result<()> {\n    let mut conn =\n        PgConnection::connect(&dotenvy::var(\"DATABASE_URL\").context(\"DATABASE_URL must be set\")?)\n            .await\n            .context(\"failed to connect to DATABASE_URL\")?;\n\n    sqlx::migrate!(\"./src/migrations\").run(&mut conn).await?;\n\n    uses_rust_decimal::create_table(&mut conn).await?;\n    uses_time::create_table(&mut conn).await?;\n\n    let user_id = sqlx::query_scalar!(\n        \"insert into users(username, password_hash) values($1, $2) returning id\",\n        \"user_foo\",\n        \"<pretend this is a password hash>\",\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    let user = sqlx::query_as!(User, \"select * from users where id = $1\", user_id)\n        .fetch_one(&mut conn)\n        .await?;\n\n    println!(\"Created user: {user:?}\");\n\n    let session =\n        uses_time::create_session(&mut conn, SessionData { user_id }, SESSION_DURATION).await?;\n\n    let session_from_id = uses_time::get_session::<SessionData>(&mut conn, session.id)\n        .await?\n        .expect(\"expected session\");\n\n    assert_eq!(session, session_from_id);\n\n    let purchase_id =\n        uses_rust_decimal::create_purchase(&mut conn, user_id, 1234u32.into(), \"Rent\").await?;\n\n    let purchase = uses_rust_decimal::get_purchase(&mut conn, purchase_id)\n        .await?\n        .expect(\"expected purchase\");\n\n    println!(\"Created purchase: {purchase:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/preferred-crates/src/migrations/01_setup.sql",
    "content": "-- We try to ensure every table has `created_at` and `updated_at` columns, which can help immensely with debugging\n-- and auditing.\n--\n-- While `created_at` can just be `default now()`, setting `updated_at` on update requires a trigger which\n-- is a lot of boilerplate. These two functions save us from writing that every time as instead we can just do\n--\n-- select trigger_updated_at('<table name>');\n--\n-- after a `CREATE TABLE`.\ncreate or replace function set_updated_at()\n    returns trigger as\n$$\nbegin\n    NEW.updated_at = now();\n    return NEW;\nend;\n$$ language plpgsql;\n\ncreate or replace function trigger_updated_at(tablename regclass)\n    returns void as\n$$\nbegin\n    execute format('CREATE TRIGGER set_updated_at\n        BEFORE UPDATE\n        ON %s\n        FOR EACH ROW\n        WHEN (OLD is distinct from NEW)\n    EXECUTE FUNCTION set_updated_at();', tablename);\nend;\n$$ language plpgsql;\n"
  },
  {
    "path": "examples/postgres/preferred-crates/src/migrations/02_users.sql",
    "content": "create table users(\n    id uuid primary key default gen_random_uuid(),\n    username text not null,\n    password_hash text not null,\n    created_at timestamptz not null default now(),\n    updated_at timestamptz\n);\n\ncreate unique index users_username_unique on users(lower(username));\n\nselect trigger_updated_at('users');\n"
  },
  {
    "path": "examples/postgres/preferred-crates/uses-rust-decimal/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-preferred-crates-uses-rust-decimal\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nrepository.workspace = true\nkeywords.workspace = true\ncategories.workspace = true\nauthors.workspace = true\n\n[dependencies]\nchrono = \"0.4\"\nrust_decimal = \"1\"\nuuid = \"1\"\n\n[dependencies.sqlx]\nworkspace = true\nfeatures = [\"runtime-tokio\", \"postgres\", \"rust_decimal\", \"chrono\", \"uuid\"]\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/postgres/preferred-crates/uses-rust-decimal/src/lib.rs",
    "content": "use chrono::{DateTime, Utc};\nuse sqlx::PgExecutor;\n\n#[derive(sqlx::FromRow, Debug)]\npub struct Purchase {\n    pub id: Uuid,\n    pub user_id: Uuid,\n    pub amount: Decimal,\n    pub description: String,\n    pub created_at: DateTime<Utc>,\n}\n\npub use rust_decimal::Decimal;\nuse uuid::Uuid;\n\npub async fn create_table(e: impl PgExecutor<'_>) -> sqlx::Result<()> {\n    sqlx::raw_sql(\n        // language=PostgreSQL\n        \"create table if not exists purchases( \\\n                id uuid primary key default gen_random_uuid(), \\\n                user_id uuid not null, \\\n                amount numeric not null check(amount > 0), \\\n                description text not null, \\\n                created_at timestamptz not null default now() \\\n             );\n        \",\n    )\n    .execute(e)\n    .await?;\n\n    Ok(())\n}\n\npub async fn create_purchase(\n    e: impl PgExecutor<'_>,\n    user_id: Uuid,\n    amount: Decimal,\n    description: &str,\n) -> sqlx::Result<Uuid> {\n    sqlx::query_scalar(\n        \"insert into purchases(user_id, amount, description) values ($1, $2, $3) returning id\",\n    )\n    .bind(user_id)\n    .bind(amount)\n    .bind(description)\n    .fetch_one(e)\n    .await\n}\n\npub async fn get_purchase(e: impl PgExecutor<'_>, id: Uuid) -> sqlx::Result<Option<Purchase>> {\n    sqlx::query_as(\"select * from purchases where id = $1\")\n        .bind(id)\n        .fetch_optional(e)\n        .await\n}\n"
  },
  {
    "path": "examples/postgres/preferred-crates/uses-time/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-preferred-crates-uses-time\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nrepository.workspace = true\nkeywords.workspace = true\ncategories.workspace = true\nauthors.workspace = true\n\n[dependencies]\nserde = \"1\"\ntime = \"0.3\"\nuuid = \"1\"\n\n[dependencies.sqlx]\nworkspace = true\nfeatures = [\"runtime-tokio\", \"postgres\", \"time\", \"json\", \"uuid\"]\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/postgres/preferred-crates/uses-time/src/lib.rs",
    "content": "use serde::de::DeserializeOwned;\nuse serde::Serialize;\nuse sqlx::PgExecutor;\nuse std::time::Duration;\nuse time::OffsetDateTime;\n\nuse sqlx::types::Json;\nuse uuid::Uuid;\n\n#[derive(sqlx::FromRow, PartialEq, Eq, Debug)]\npub struct Session<D> {\n    pub id: Uuid,\n    #[sqlx(json)]\n    pub data: D,\n    pub created_at: OffsetDateTime,\n    pub expires_at: OffsetDateTime,\n}\n\npub async fn create_table(e: impl PgExecutor<'_>) -> sqlx::Result<()> {\n    sqlx::raw_sql(\n        // language=PostgreSQL\n        \"create table if not exists sessions( \\\n                id uuid primary key default gen_random_uuid(), \\\n                data jsonb not null,\n                created_at timestamptz not null default now(),\n                expires_at timestamptz not null\n             )\",\n    )\n    .execute(e)\n    .await?;\n\n    Ok(())\n}\n\npub async fn create_session<D: Serialize>(\n    e: impl PgExecutor<'_>,\n    data: D,\n    valid_duration: Duration,\n) -> sqlx::Result<Session<D>> {\n    // Round down to the nearest second because\n    // Postgres doesn't support precision higher than 1 microsecond anyway.\n    let created_at = OffsetDateTime::now_utc()\n        .replace_nanosecond(0)\n        .expect(\"0 nanoseconds should be in range\");\n\n    let expires_at = created_at + valid_duration;\n\n    let id: Uuid = sqlx::query_scalar(\n        \"insert into sessions(data, created_at, expires_at) \\\n             values ($1, $2, $3) \\\n             returning id\",\n    )\n    .bind(Json(&data))\n    .bind(created_at)\n    .bind(expires_at)\n    .fetch_one(e)\n    .await?;\n\n    Ok(Session {\n        id,\n        data,\n        created_at,\n        expires_at,\n    })\n}\n\npub async fn get_session<D: DeserializeOwned + Send + Unpin + 'static>(\n    e: impl PgExecutor<'_>,\n    id: Uuid,\n) -> sqlx::Result<Option<Session<D>>> {\n    sqlx::query_as(\"select id, data, created_at, expires_at from sessions where id = $1\")\n        .bind(id)\n        .fetch_optional(e)\n        .await\n}\n"
  },
  {
    "path": "examples/postgres/todos/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-todos\"\nversion = \"0.1.0\"\nedition = \"2018\"\nworkspace = \"../../../\"\n\n[dependencies]\nanyhow = \"1.0\"\nsqlx = { path = \"../../../\", features = [ \"postgres\", \"runtime-tokio\", \"tls-native-tls\" ] }\nclap = { version = \"4\", features = [\"derive\"] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\ndotenvy = \"0.15.0\"\n"
  },
  {
    "path": "examples/postgres/todos/README.md",
    "content": "# TODOs Example\n\n## Setup\n\n1. Declare the database URL\n\n    ```\n    export DATABASE_URL=\"postgres://postgres:password@localhost/todos\"\n    ```\n\n2. Create the database.\n\n    ```\n    $ sqlx db create\n    ```\n\n3. Run sql migrations\n\n    ```\n    $ sqlx migrate run\n    ```\n\n## Usage\n\nAdd a todo \n\n```\ncargo run -- add \"todo description\"\n```\n\nComplete a todo.\n\n```\ncargo run -- done <todo id>\n```\n\nList all todos\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/postgres/todos/migrations/20200718111257_todos.sql",
    "content": "CREATE TABLE IF NOT EXISTS todos\n(\n    id          BIGSERIAL PRIMARY KEY,\n    description TEXT    NOT NULL,\n    done        BOOLEAN NOT NULL DEFAULT FALSE\n);\n"
  },
  {
    "path": "examples/postgres/todos/src/main.rs",
    "content": "use clap::{Parser, Subcommand};\nuse sqlx::postgres::PgPool;\nuse std::env;\n\n#[derive(Parser)]\nstruct Args {\n    #[command(subcommand)]\n    cmd: Option<Command>,\n}\n\n#[derive(Subcommand)]\nenum Command {\n    Add { description: String },\n    Done { id: i64 },\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    let args = Args::parse();\n    let pool = PgPool::connect(&env::var(\"DATABASE_URL\")?).await?;\n\n    match args.cmd {\n        Some(Command::Add { description }) => {\n            println!(\"Adding new todo with description '{description}'\");\n            let todo_id = add_todo(&pool, description).await?;\n            println!(\"Added new todo with id {todo_id}\");\n        }\n        Some(Command::Done { id }) => {\n            println!(\"Marking todo {id} as done\");\n            if complete_todo(&pool, id).await? {\n                println!(\"Todo {id} is marked as done\");\n            } else {\n                println!(\"Invalid id {id}\");\n            }\n        }\n        None => {\n            println!(\"Printing list of all todos\");\n            list_todos(&pool).await?;\n        }\n    }\n\n    Ok(())\n}\n\nasync fn add_todo(pool: &PgPool, description: String) -> anyhow::Result<i64> {\n    let rec = sqlx::query!(\n        r#\"\nINSERT INTO todos ( description )\nVALUES ( $1 )\nRETURNING id\n        \"#,\n        description\n    )\n    .fetch_one(pool)\n    .await?;\n\n    Ok(rec.id)\n}\n\nasync fn complete_todo(pool: &PgPool, id: i64) -> anyhow::Result<bool> {\n    let rows_affected = sqlx::query!(\n        r#\"\nUPDATE todos\nSET done = TRUE\nWHERE id = $1\n        \"#,\n        id\n    )\n    .execute(pool)\n    .await?\n    .rows_affected();\n\n    Ok(rows_affected > 0)\n}\n\nasync fn list_todos(pool: &PgPool) -> anyhow::Result<()> {\n    let recs = sqlx::query!(\n        r#\"\nSELECT id, description, done\nFROM todos\nORDER BY id\n        \"#\n    )\n    .fetch_all(pool)\n    .await?;\n\n    for rec in recs {\n        println!(\n            \"- [{}] {}: {}\",\n            if rec.done { \"x\" } else { \" \" },\n            rec.id,\n            &rec.description,\n        );\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/postgres/transaction/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-postgres-transaction\"\nversion = \"0.1.0\"\nedition = \"2021\"\nworkspace = \"../../../\"\n\n[dependencies]\nsqlx = { path = \"../../../\", features = [ \"postgres\", \"runtime-tokio\", \"tls-native-tls\" ] }\ntokio = { version = \"1.20.0\", features = [\"rt-multi-thread\", \"macros\"]}\n"
  },
  {
    "path": "examples/postgres/transaction/README.md",
    "content": "# Postgres Transaction Example\n\nA simple example demonstrating how to obtain and roll back a transaction with postgres.\n\n## Usage\n\nDeclare the database URL. This example does not include any reading or writing of data.\n\n```\nexport DATABASE_URL=\"postgres://postgres@localhost/postgres\"\n```\n\nRun.\n\n```\ncargo run\n```\n\n"
  },
  {
    "path": "examples/postgres/transaction/migrations/20200718111257_todos.sql",
    "content": "CREATE TABLE IF NOT EXISTS todos\n(\n    id          BIGSERIAL PRIMARY KEY,\n    description TEXT    NOT NULL,\n    done        BOOLEAN NOT NULL DEFAULT FALSE\n);\n"
  },
  {
    "path": "examples/postgres/transaction/src/main.rs",
    "content": "use sqlx::query;\n\nasync fn insert_and_verify(\n    transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,\n    test_id: i64,\n) -> Result<(), Box<dyn std::error::Error>> {\n    query!(\n        r#\"INSERT INTO todos (id, description)\n        VALUES ( $1, $2 )\n        \"#,\n        test_id,\n        \"test todo\"\n    )\n    // In 0.7, `Transaction` can no longer implement `Executor` directly,\n    // so it must be dereferenced to the internal connection type.\n    .execute(&mut **transaction)\n    .await?;\n\n    // check that inserted todo can be fetched inside the uncommitted transaction\n    let _ = query!(r#\"SELECT FROM todos WHERE id = $1\"#, test_id)\n        .fetch_one(&mut **transaction)\n        .await?;\n\n    Ok(())\n}\n\nasync fn explicit_rollback_example(\n    pool: &sqlx::PgPool,\n    test_id: i64,\n) -> Result<(), Box<dyn std::error::Error>> {\n    let mut transaction = pool.begin().await?;\n\n    insert_and_verify(&mut transaction, test_id).await?;\n\n    transaction.rollback().await?;\n\n    Ok(())\n}\n\nasync fn implicit_rollback_example(\n    pool: &sqlx::PgPool,\n    test_id: i64,\n) -> Result<(), Box<dyn std::error::Error>> {\n    let mut transaction = pool.begin().await?;\n\n    insert_and_verify(&mut transaction, test_id).await?;\n\n    // no explicit rollback here but the transaction object is dropped at the end of the scope\n    Ok(())\n}\n\nasync fn commit_example(\n    pool: &sqlx::PgPool,\n    test_id: i64,\n) -> Result<(), Box<dyn std::error::Error>> {\n    let mut transaction = pool.begin().await?;\n\n    insert_and_verify(&mut transaction, test_id).await?;\n\n    transaction.commit().await?;\n\n    Ok(())\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let conn_str =\n        std::env::var(\"DATABASE_URL\").expect(\"Env var DATABASE_URL is required for this example.\");\n    let pool = sqlx::PgPool::connect(&conn_str).await?;\n\n    let test_id = 1;\n\n    // remove any old values that might be in the table already with this id from a previous run\n    let _ = query!(r#\"DELETE FROM todos WHERE id = $1\"#, test_id)\n        .execute(&pool)\n        .await?;\n\n    explicit_rollback_example(&pool, test_id).await?;\n\n    // check that inserted todo is not visible outside the transaction after explicit rollback\n    let inserted_todo = query!(r#\"SELECT FROM todos WHERE id = $1\"#, test_id)\n        .fetch_one(&pool)\n        .await;\n\n    assert!(inserted_todo.is_err());\n\n    implicit_rollback_example(&pool, test_id).await?;\n\n    // check that inserted todo is not visible outside the transaction after implicit rollback\n    let inserted_todo = query!(r#\"SELECT FROM todos WHERE id = $1\"#, test_id)\n        .fetch_one(&pool)\n        .await;\n\n    assert!(inserted_todo.is_err());\n\n    commit_example(&pool, test_id).await?;\n\n    // check that inserted todo is visible outside the transaction after commit\n    let inserted_todo = query!(r#\"SELECT FROM todos WHERE id = $1\"#, test_id)\n        .fetch_one(&pool)\n        .await;\n\n    assert!(inserted_todo.is_ok());\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/sqlite/extension/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-sqlite-extension\"\nversion = \"0.1.0\"\nlicense.workspace = true\nedition.workspace = true\nrepository.workspace = true\nkeywords.workspace = true\ncategories.workspace = true\nauthors.workspace = true\n\n[dependencies]\nsqlx = { path = \"../../../\", features = [ \"sqlite\", \"runtime-tokio\", \"tls-native-tls\", \"sqlx-toml\"] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\nanyhow = \"1.0\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "examples/sqlite/extension/download-extension.sh",
    "content": "#!/bin/bash\n\n# This grabs a pre-compiled version of the extension used in this\n# example, and stores it in a temporary directory. That's a bit\n# unusual. Normally, any extensions you need will be installed into a\n# directory on the library search path, either by using the system\n# package manager or by compiling and installing it yourself.\n\nmkdir /tmp/sqlite3-lib && wget -O /tmp/sqlite3-lib/ipaddr.so https://github.com/nalgeon/sqlean/releases/download/0.15.2/ipaddr.so\n"
  },
  {
    "path": "examples/sqlite/extension/migrations/20250203094951_addresses.sql",
    "content": "create table addresses (address text, family integer);\n\n-- The `ipfamily` function is provided by the\n-- [ipaddr](https://github.com/nalgeon/sqlean/blob/main/docs/ipaddr.md)\n-- sqlite extension, and so this migration can not run if that\n-- extension is not loaded.\ninsert into addresses (address, family) values\n  ('fd04:3d29:9f41::1', ipfamily('fd04:3d29:9f41::1')),\n  ('10.0.0.1', ipfamily('10.0.0.1')),\n  ('10.0.0.2', ipfamily('10.0.0.2')),\n  ('fd04:3d29:9f41::2', ipfamily('fd04:3d29:9f41::2')),\n  ('fd04:3d29:9f41::3', ipfamily('fd04:3d29:9f41::3')),\n  ('10.0.0.3', ipfamily('10.0.0.3')),\n  ('fd04:3d29:9f41::4', ipfamily('fd04:3d29:9f41::4')),\n  ('fd04:3d29:9f41::5', ipfamily('fd04:3d29:9f41::5')),\n  ('fd04:3d29:9f41::6', ipfamily('fd04:3d29:9f41::6')),\n  ('10.0.0.4', ipfamily('10.0.0.4')),\n  ('10.0.0.5', ipfamily('10.0.0.5')),\n  ('10.0.0.6', ipfamily('10.0.0.6')),\n  ('10.0.0.7', ipfamily('10.0.0.7')),\n  ('fd04:3d29:9f41::7', ipfamily('fd04:3d29:9f41::7')),\n  ('fd04:3d29:9f41::8', ipfamily('fd04:3d29:9f41::8')),\n  ('10.0.0.8', ipfamily('10.0.0.8')),\n  ('fd04:3d29:9f41::9', ipfamily('fd04:3d29:9f41::9')),\n  ('10.0.0.9', ipfamily('10.0.0.9'));\n"
  },
  {
    "path": "examples/sqlite/extension/sqlx.toml",
    "content": "[common.drivers.sqlite]\n# Including the full path to the extension is somewhat unusual,\n# because normally an extension will be installed in a standard\n# directory which is part of the library search path. If that were the\n# case here, the unsafe-load-extensions value could just be `[\"ipaddr\"]`\n#\n# When the extension file is installed in a non-standard location, as\n# in this example, there are two options:\n# * Provide the full path the the extension, as seen below.\n# * Add the non-standard location to the library search path, which on\n#   Linux means adding it to the LD_LIBRARY_PATH environment variable.\nunsafe-load-extensions = [\"/tmp/sqlite3-lib/ipaddr\"]\n"
  },
  {
    "path": "examples/sqlite/extension/src/main.rs",
    "content": "use std::str::FromStr;\n\nuse sqlx::{\n    query,\n    sqlite::{SqliteConnectOptions, SqlitePool},\n};\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    let opts = SqliteConnectOptions::from_str(&std::env::var(\"DATABASE_URL\")?)?\n        // The sqlx.toml file controls loading extensions for the CLI\n        // and for the query checking macros, *not* for the\n        // application while it's running. Thus, if we want the\n        // extension to be available during program execution, we need\n        // to load it.\n        //\n        // Note that while in this case the extension path is the same\n        // when checking the program (sqlx.toml) and when running it\n        // (here), this is not required. The runtime environment can\n        // be entirely different from the development one.\n        //\n        // The extension can be described with a full path, as seen\n        // here, but in many cases that will not be necessary. As long\n        // as the extension is installed in a directory on the library\n        // search path, it is sufficient to just provide the extension\n        // name, like \"ipaddr\"\n        .extension(\"/tmp/sqlite3-lib/ipaddr\");\n\n    let db = SqlitePool::connect_with(opts).await?;\n\n    // We're not running the migrations here, for the sake of brevity\n    // and to confirm that the needed extension was loaded during the\n    // CLI migrate operation. It would not be unusual to run the\n    // migrations here as well, though, using the database connection\n    // we just configured.\n\n    query!(\n        \"insert into addresses (address, family) values (?1, ipfamily(?1))\",\n        \"10.0.0.10\"\n    )\n    .execute(&db)\n    .await?;\n\n    println!(\"Query which requires the extension was successfully executed.\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/sqlite/todos/Cargo.toml",
    "content": "[package]\nname = \"sqlx-example-sqlite-todos\"\nversion = \"0.1.0\"\nedition = \"2018\"\nworkspace = \"../../../\"\n\n[dependencies]\nanyhow = \"1.0\"\nsqlx = { path = \"../../../\", features = [ \"sqlite\", \"runtime-tokio\", \"tls-native-tls\" ] }\nclap = { version = \"4\", features = [\"derive\"] }\ntokio = { version = \"1.20.0\", features = [\"rt\", \"macros\"]}\n"
  },
  {
    "path": "examples/sqlite/todos/README.md",
    "content": "# TODOs Example\n\n## Setup\n\n1. Declare the database URL\n\n    ```\n    export DATABASE_URL=\"sqlite:todos.db\"\n    ```\n\n2. Create the database.\n\n    ```\n    $ sqlx db create\n    ```\n\n3. Run sql migrations\n\n    ```\n    $ sqlx migrate run\n    ```\n\n## Usage\n\nAdd a todo \n\n```\ncargo run -- add \"todo description\"\n```\n\nComplete a todo.\n\n```\ncargo run -- done <todo id>\n```\n\nList all todos\n\n```\ncargo run\n```\n"
  },
  {
    "path": "examples/sqlite/todos/migrations/20200718111257_todos.sql",
    "content": "CREATE TABLE IF NOT EXISTS todos\n(\n    id          INTEGER PRIMARY KEY NOT NULL,\n    description TEXT                NOT NULL,\n    done        BOOLEAN             NOT NULL DEFAULT 0\n);\n"
  },
  {
    "path": "examples/sqlite/todos/src/main.rs",
    "content": "use clap::{Parser, Subcommand};\nuse sqlx::sqlite::SqlitePool;\nuse std::env;\n\n#[derive(Parser)]\nstruct Args {\n    #[command(subcommand)]\n    cmd: Option<Command>,\n}\n\n#[derive(Subcommand)]\nenum Command {\n    Add { description: String },\n    Done { id: i64 },\n}\n\n#[tokio::main(flavor = \"current_thread\")]\nasync fn main() -> anyhow::Result<()> {\n    let args = Args::parse();\n    let pool = SqlitePool::connect(&env::var(\"DATABASE_URL\")?).await?;\n\n    match args.cmd {\n        Some(Command::Add { description }) => {\n            println!(\"Adding new todo with description '{description}'\");\n            let todo_id = add_todo(&pool, description).await?;\n            println!(\"Added new todo with id {todo_id}\");\n        }\n        Some(Command::Done { id }) => {\n            println!(\"Marking todo {id} as done\");\n            if complete_todo(&pool, id).await? {\n                println!(\"Todo {id} is marked as done\");\n            } else {\n                println!(\"Invalid id {id}\");\n            }\n        }\n        None => {\n            println!(\"Printing list of all todos\");\n            list_todos(&pool).await?;\n        }\n    }\n\n    Ok(())\n}\n\nasync fn add_todo(pool: &SqlitePool, description: String) -> anyhow::Result<i64> {\n    let mut conn = pool.acquire().await?;\n\n    // Insert the task, then obtain the ID of this row\n    let id = sqlx::query!(\n        r#\"\nINSERT INTO todos ( description )\nVALUES ( ?1 )\n        \"#,\n        description\n    )\n    .execute(&mut *conn)\n    .await?\n    .last_insert_rowid();\n\n    Ok(id)\n}\n\nasync fn complete_todo(pool: &SqlitePool, id: i64) -> anyhow::Result<bool> {\n    let rows_affected = sqlx::query!(\n        r#\"\nUPDATE todos\nSET done = TRUE\nWHERE id = ?1\n        \"#,\n        id\n    )\n    .execute(pool)\n    .await?\n    .rows_affected();\n\n    Ok(rows_affected > 0)\n}\n\nasync fn list_todos(pool: &SqlitePool) -> anyhow::Result<()> {\n    let recs = sqlx::query!(\n        r#\"\nSELECT id, description, done\nFROM todos\nORDER BY id\n        \"#\n    )\n    .fetch_all(pool)\n    .await?;\n\n    for rec in recs {\n        println!(\n            \"- [{}] {}: {}\",\n            if rec.done { \"x\" } else { \" \" },\n            rec.id,\n            &rec.description,\n        );\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "examples/x.py",
    "content": "#!/usr/bin/env python3\n\nimport sys\nimport os\nfrom os import path\n\n# base dir of sqlx workspace\ndir_workspace = path.dirname(path.dirname(path.realpath(__file__)))\n\n# dir of tests\ndir_tests = path.join(dir_workspace, \"tests\")\n\n# extend import path to tests/\nsys.path.append(dir_tests)\n\nimport subprocess\nimport time\nimport argparse\nfrom docker import start_database\n\nparser = argparse.ArgumentParser()\nparser.add_argument(\"-p\", \"--project\")\nparser.add_argument(\"-l\", \"--list-projects\", action=\"store_true\")\n\nargv, unknown = parser.parse_known_args()\n\n\ndef run(command, env=None, cwd=None, display=None):\n    if display:\n        print(f\"\\x1b[93m $ {display}\\x1b[0m\")\n\n    else:\n        print(f\"\\x1b[93m $ {command}\\x1b[0m\")\n\n    res = subprocess.run(\n        command.split(\" \"),\n        env=dict(**os.environ, **env),\n        cwd=cwd,\n    )\n\n    if res.returncode != 0:\n        sys.exit(res.returncode)\n\n\ndef sqlx(command, url, cwd=None):\n    run(f\"cargo --quiet run -p sqlx-cli --bin sqlx -- {command}\", cwd=cwd, env={\"DATABASE_URL\": url},\n        display=f\"sqlx {command}\")\n\n\ndef project(name, database=None, driver=None):\n    if argv.list_projects:\n        print(f\"{name}\")\n        return\n\n    if argv.project and name != argv.project:\n        return\n\n    print(f\"\\x1b[2m # {name}\\x1b[0m\")\n\n    env = {}\n\n    cwd = path.join(dir_workspace, \"examples\", name)\n\n    if database is not None:\n        database_url = start_database(driver, database, cwd=cwd)\n        env[\"DATABASE_URL\"] = database_url\n\n        # show the database url\n        print(f\"\\x1b[94m @ {database_url}\\x1b[0m\")\n\n        # database drop (if exists)\n        sqlx(\"db drop -y\", database_url, cwd=cwd)\n\n        # database create\n        sqlx(\"db create\", database_url, cwd=cwd)\n\n        # migrate\n        sqlx(\"migrate run\", database_url, cwd=cwd)\n\n    # check\n    run(\"cargo check\", cwd=cwd, env=env)\n\n\n# todos\nproject(\"mysql/todos\", driver=\"mysql_8\", database=\"todos\")\nproject(\"postgres/todos\", driver=\"postgres_12\", database=\"todos\")\nproject(\"sqlite/todos\", driver=\"sqlite\", database=\"todos.db\")\nproject(\"sqlite/extension\", driver=\"sqlite\", database=\"extension.db\")\n"
  },
  {
    "path": "gen-changelog.sh",
    "content": "# Requires Github CLI and `jq`\n# Usage: `./gen-changelog.sh YYYY-mm-dd`\n# Generates changelog entries for all PRs merged on or after the given date.\nset -e\n\nPULLS='[]'\nCURSOR='null'\n\nMIN_MERGED_AT=$(date --date=\"$1\" +%s)\n\nwhile true\ndo\n  # Use the GraphQL API to paginate merged pull requests.\n  # The REST API doesn't allow filtering only merged pull requests.\n  # We scan all merged pull requests from the beginning because it's not unheard of to have a very old PR finally get\n  # merged; e.g. #1081, merged a year and a half after it was opened.\n  if [ \"$CURSOR\" != \"null\" ];\n  then\n    PAGE=$(gh api graphql -f after=\"$CURSOR\" -f query='query($after: String) {\n               repository(owner: \"launchbadge\", name: \"sqlx\") {\n                 pullRequests(first:100,orderBy: {field:CREATED_AT, direction:ASC},states:MERGED, after: $after) {\n                   nodes {\n                     number\n                     author { login }\n                     title\n                     url\n                     mergedAt\n                   }\n                   pageInfo {\n                     hasNextPage\n                     endCursor\n                   }\n                 }\n               }\n             }');\n  else\n        PAGE=$(gh api graphql -f query='query {\n                   repository(owner: \"launchbadge\", name: \"sqlx\") {\n                     pullRequests(first:100,orderBy: {field:CREATED_AT, direction:ASC},states:MERGED) {\n                       nodes {\n                         number\n                         author { login }\n                         title\n                         url\n                         mergedAt\n                       }\n                       pageInfo {\n                         hasNextPage\n                         endCursor\n                       }\n                     }\n                   }\n                 }');\n  fi\n\n  CURSOR=$(echo \"$PAGE\" | jq -r '.data.repository.pullRequests.pageInfo.endCursor');\n\n  HAS_NEXT_PAGE=$(echo \"$PAGE\" | jq '.data.repository.pullRequests.pageInfo.hasNextPage');\n\n  PULLS=$(echo \"$PAGE\" | jq \"$PULLS + (.data.repository.pullRequests.nodes | map(select(.mergedAt | fromdate >= $MIN_MERGED_AT)))\");\n\n  # can't use `\"$CURSOR\" == 'null'` because the last page still gives a valid cursor\n  if ! $HAS_NEXT_PAGE; then break; fi;\ndone\n\nCOUNT=$(echo \"$PULLS\" | jq \"length\");\n\necho \"Found $COUNT pull requests merged on or after $1\\n\"\n\nif [ -z $COUNT ]; then exit 0; fi;\n\necho \"Entries:\"\necho \"$PULLS\" | jq -r 'map(\"* [[#\\(.number)]]: \\(.title) [[@\\(.author.login)]]\") | join(\"\\n\")'\n\necho \"\\nLinks:\"\necho \"$PULLS\" | jq -r 'map(\"[#\\(.number)]: \\(.url)\") | join(\"\\n\")'\n\necho \"\\nNew Authors:\"\nDUPE_AUTHORS=''\n\n# Generate link entries for new authors at the end of the changelog.\necho \"$PULLS\" | jq -r '.[].author.login' | while read author; do\n  author_url=\"https://github.com/$author\"\n  author_entry=\"[@$author]: $author_url\"\n\n  # Check if the entry already exists in the changelog or in our list of new authors.\n  if grep -qF \"$author_entry\" CHANGELOG.md || echo \"$DUPE_AUTHORS\" | grep -qF \"$author_entry\";\n  then continue;\n  fi;\n\n  DUPE_AUTHORS=\"$DUPE_AUTHORS$author_entry\\n\"\n  echo $author_entry\ndone\n"
  },
  {
    "path": "rust-toolchain.toml",
    "content": "# Note: should NOT increase during a minor/patch release cycle\n[toolchain]\nchannel = \"1.86\"\nprofile = \"minimal\"\n"
  },
  {
    "path": "sqlx-cli/Cargo.toml",
    "content": "[package]\nname = \"sqlx-cli\"\nversion.workspace = true\ndescription = \"Command-line utility for SQLx, the Rust SQL toolkit.\"\nedition = \"2021\"\nreadme = \"README.md\"\nhomepage = \"https://github.com/launchbadge/sqlx\"\nrepository = \"https://github.com/launchbadge/sqlx\"\nkeywords = [\"database\", \"postgres\", \"database-management\", \"migration\"]\ncategories = [\"database\", \"command-line-utilities\"]\nlicense = \"MIT OR Apache-2.0\"\ndefault-run = \"sqlx\"\nauthors = [\n    \"Jesper Axelsson <jesperaxe@gmail.com>\",\n    \"Austin Bonander <austin.bonander@gmail.com>\",\n]\nrust-version.workspace = true\n\n[[bin]]\nname = \"sqlx\"\npath = \"src/bin/sqlx.rs\"\n\n# enables invocation as `cargo sqlx`; required for `prepare` subcommand\n[[bin]]\nname = \"cargo-sqlx\"\npath = \"src/bin/cargo-sqlx.rs\"\n\n[dependencies]\ndotenvy = \"0.15.0\"\ntokio = { version = \"1.15.0\", features = [\"macros\", \"rt\", \"rt-multi-thread\", \"signal\"] }\nfutures-util = { version = \"0.3.19\", features = [\"alloc\"] }\nclap = { version = \"4.3.10\", features = [\"derive\", \"env\", \"wrap_help\"] }\nclap_complete = { version = \"4.3.1\", optional = true }\nchrono = { version = \"0.4.19\", default-features = false, features = [\"clock\"] }\nanyhow = \"1.0.52\"\nconsole = \"0.15.0\"\ndialoguer = { version = \"0.11\", default-features = false }\nserde_json = \"1.0.73\"\nglob = \"0.3.0\"\nopenssl = { version = \"0.10.46\", optional = true }\ncargo_metadata = \"0.18.1\"\nfiletime = \"0.2\"\n\nbackoff = { version = \"0.4.0\", features = [\"futures\", \"tokio\"] }\n\n[dependencies.sqlx]\nworkspace = true\ndefault-features = false\nfeatures = [\n    \"runtime-tokio\",\n    \"migrate\",\n    \"any\",\n]\n\n[features]\ndefault = [\"postgres\", \"sqlite\", \"mysql\", \"native-tls\", \"completions\", \"sqlx-toml\"]\n\n# TLS options\nrustls = [\"sqlx/tls-rustls\"]\nnative-tls = [\"sqlx/tls-native-tls\"]\n\n# databases\nmysql = [\"sqlx/mysql\"]\npostgres = [\"sqlx/postgres\"]\nsqlite = [\"sqlx/sqlite\", \"_sqlite\"]\nsqlite-unbundled = [\"sqlx/sqlite-unbundled\", \"_sqlite\"]\n\n# workaround for musl + openssl issues\nopenssl-vendored = [\"openssl/vendored\"]\n\ncompletions = [\"dep:clap_complete\"]\n\nsqlx-toml = [\"sqlx/sqlx-toml\"]\n\n# Conditional compilation only\n_sqlite = []\n\n[dev-dependencies]\nassert_cmd = \"2.1.1\"\ntempfile = \"3.10.1\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "sqlx-cli/README.md",
    "content": "# SQLx CLI\n\nSQLx's associated command-line utility for managing databases, migrations, and enabling \"offline\"\nmode with `sqlx::query!()` and friends.\n\n## Install\n\n### With Rust toolchain\n\n```bash\n# supports all databases supported by SQLx\n$ cargo install sqlx-cli\n\n# only for postgres\n$ cargo install sqlx-cli --no-default-features --features native-tls,postgres\n\n# use vendored OpenSSL (build from source)\n$ cargo install sqlx-cli --features openssl-vendored\n\n# use Rustls rather than OpenSSL (be sure to add the features for the databases you intend to use!)\n$ cargo install sqlx-cli --no-default-features --features rustls\n\n# only for sqlite and use the system sqlite library\n$ cargo install sqlx-cli --no-default-features --features sqlite-unbundled\n```\n\n## Usage\n\nAll commands require that a database url is provided. This can be done either with the `--database-url` command line option or by setting `DATABASE_URL`, either in the environment or in a `.env` file\nin the current working directory.\n\nFor more details, run `sqlx <command> --help`.\n\n```dotenv\n# Postgres\nDATABASE_URL=postgres://postgres@localhost/my_database\n```\n\n### Create/drop the database at `DATABASE_URL`\n\n```bash\nsqlx database create\nsqlx database drop\n```\n\n---\n\n### Create and run migrations\n\n```bash\nsqlx migrate add <name>\n```\n\nCreates a new file in `migrations/<timestamp>-<name>.sql`. Add your database schema changes to\nthis new file.\n\n---\n\n```bash\nsqlx migrate run\n```\n\nCompares the migration history of the running database against the `migrations/` folder and runs\nany scripts that are still pending.\n\n---\n\nUsers can provide the directory for the migration scripts to `sqlx migrate` subcommands with the `--source` flag.\n\n```bash\nsqlx migrate info --source ../relative/migrations\n```\n\n---\n\n### Reverting Migrations\n\nIf you would like to create _reversible_ migrations with corresponding \"up\" and \"down\" scripts, you use the `-r` flag when creating the first migration:\n\n```bash\n$ sqlx migrate add -r <name>\nCreating migrations/20211001154420_<name>.up.sql\nCreating migrations/20211001154420_<name>.down.sql\n```\n\nAfter that, you can run these as above:\n\n```bash\n$ sqlx migrate run\nApplied migrations/20211001154420 <name> (32.517835ms)\n```\n\nAnd reverts work as well:\n\n```bash\n$ sqlx migrate revert\nApplied 20211001154420/revert <name>\n```\n\n**Note**: All the subsequent migrations will be reversible as well.\n\n```bash\n$ sqlx migrate add <name1>\nCreating migrations/20211001154420_<name>.up.sql\nCreating migrations/20211001154420_<name>.down.sql\n```\n\n### Enable building in \"offline mode\" with `query!()`\n\nThere are 2 steps to building with \"offline mode\":\n\n1. Save query metadata for offline usage\n    - `cargo sqlx prepare`\n2. Build\n\nNote: Saving query metadata must be run as `cargo sqlx`.\n\n```bash\ncargo sqlx prepare\n```\n\nInvoking `prepare` saves query metadata to `.sqlx` in the current directory.\nFor workspaces where several crates are using query macros, pass the `--workspace` flag\nto generate a single `.sqlx` directory at the root of the workspace.\n\n```bash\ncargo sqlx prepare --workspace\n```\n\nCheck this directory into version control and an active database connection will \nno longer be needed to build your project.\n\n---\n\n```bash\ncargo sqlx prepare --check\n# OR\ncargo sqlx prepare --check --workspace\n```\n\nExits with a nonzero exit status if the data in `.sqlx` is out of date with the current\ndatabase schema or queries in the project. Intended for use in Continuous Integration.\n\n### Force building in offline mode\n\nThe presence of a `DATABASE_URL` environment variable will take precedence over the presence of `.sqlx`, meaning SQLx will default to building against a database if it can. To make sure an accidentally-present `DATABASE_URL` environment variable or `.env` file does not\nresult in `cargo build` (trying to) access the database, you can set the `SQLX_OFFLINE` environment\nvariable to `true`.\n\nIf you want to make this the default, just add it to your `.env` file. `cargo sqlx prepare` will\nstill do the right thing and connect to the database.\n\n### Include queries behind feature flags (such as queries inside of tests)\n\nIn order for sqlx to be able to find queries behind certain feature flags or in tests, you need to turn them\non by passing arguments to `cargo`.\n\nThis is how you would turn all targets and features on.\n\n```bash\ncargo sqlx prepare -- --all-targets --all-features\n```\n"
  },
  {
    "path": "sqlx-cli/src/bin/cargo-sqlx.rs",
    "content": "use clap::Parser;\nuse console::style;\nuse sqlx_cli::Opt;\nuse std::process;\n\n// cargo invokes this binary as `cargo-sqlx sqlx <args>`\n// so the parser below is defined with that in mind\n#[derive(Parser, Debug)]\n#[clap(bin_name = \"cargo\")]\nenum Cli {\n    Sqlx(Opt),\n}\n\n#[tokio::main]\nasync fn main() {\n    sqlx_cli::maybe_apply_dotenv();\n\n    sqlx::any::install_default_drivers();\n\n    let Cli::Sqlx(opt) = Cli::parse();\n\n    if let Err(error) = sqlx_cli::run(opt).await {\n        println!(\"{} {}\", style(\"error:\").bold().red(), error);\n        process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sqlx-cli/src/bin/sqlx.rs",
    "content": "use clap::Parser;\nuse console::style;\nuse sqlx_cli::Opt;\n\n#[tokio::main]\nasync fn main() {\n    // Checks for `--no-dotenv` before parsing.\n    sqlx_cli::maybe_apply_dotenv();\n\n    sqlx::any::install_default_drivers();\n\n    let opt = Opt::parse();\n\n    // no special handling here\n    if let Err(error) = sqlx_cli::run(opt).await {\n        println!(\"{} {}\", style(\"error:\").bold().red(), error);\n        std::process::exit(1);\n    }\n}\n"
  },
  {
    "path": "sqlx-cli/src/completions.rs",
    "content": "use std::io;\n\nuse clap::CommandFactory;\nuse clap_complete::{generate, Shell};\n\nuse crate::opt::Command;\n\npub fn run(shell: Shell) {\n    generate(shell, &mut Command::command(), \"sqlx\", &mut io::stdout())\n}\n"
  },
  {
    "path": "sqlx-cli/src/database.rs",
    "content": "use crate::opt::{ConnectOpts, MigrationSourceOpt};\nuse crate::{migrate, Config};\nuse console::{style, Term};\nuse dialoguer::Confirm;\nuse sqlx::any::Any;\nuse sqlx::migrate::MigrateDatabase;\nuse std::{io, mem};\nuse tokio::task;\n\npub async fn create(connect_opts: &ConnectOpts) -> anyhow::Result<()> {\n    // NOTE: only retry the idempotent action.\n    // We're assuming that if this succeeds, then any following operations should also succeed.\n    let exists = crate::retry_connect_errors(connect_opts, Any::database_exists).await?;\n\n    if !exists {\n        #[cfg(feature = \"_sqlite\")]\n        sqlx::sqlite::CREATE_DB_WAL.store(\n            connect_opts.sqlite_create_db_wal,\n            std::sync::atomic::Ordering::Release,\n        );\n\n        Any::create_database(connect_opts.expect_db_url()?).await?;\n    }\n\n    Ok(())\n}\n\npub async fn drop(connect_opts: &ConnectOpts, confirm: bool, force: bool) -> anyhow::Result<()> {\n    if confirm && !ask_to_continue_drop(connect_opts.expect_db_url()?.to_owned()).await {\n        return Ok(());\n    }\n\n    // NOTE: only retry the idempotent action.\n    // We're assuming that if this succeeds, then any following operations should also succeed.\n    let exists = crate::retry_connect_errors(connect_opts, Any::database_exists).await?;\n\n    if exists {\n        if force {\n            Any::force_drop_database(connect_opts.expect_db_url()?).await?;\n        } else {\n            Any::drop_database(connect_opts.expect_db_url()?).await?;\n        }\n    }\n\n    Ok(())\n}\n\npub async fn reset(\n    config: &Config,\n    migration_source: &MigrationSourceOpt,\n    connect_opts: &ConnectOpts,\n    confirm: bool,\n    force: bool,\n) -> anyhow::Result<()> {\n    drop(connect_opts, confirm, force).await?;\n    setup(config, migration_source, connect_opts).await\n}\n\npub async fn setup(\n    config: &Config,\n    migration_source: &MigrationSourceOpt,\n    connect_opts: &ConnectOpts,\n) -> anyhow::Result<()> {\n    create(connect_opts).await?;\n    migrate::run(config, migration_source, connect_opts, false, false, None).await\n}\n\nasync fn ask_to_continue_drop(db_url: String) -> bool {\n    // If the setup operation is cancelled while we are waiting for the user to decide whether\n    // or not to drop the database, this will restore the terminal's cursor to its normal state.\n    struct RestoreCursorGuard {\n        disarmed: bool,\n    }\n\n    impl Drop for RestoreCursorGuard {\n        fn drop(&mut self) {\n            if !self.disarmed {\n                Term::stderr().show_cursor().unwrap()\n            }\n        }\n    }\n\n    let mut guard = RestoreCursorGuard { disarmed: false };\n\n    let decision_result = task::spawn_blocking(move || {\n        Confirm::new()\n            .with_prompt(format!(\"Drop database at {}?\", style(&db_url).cyan()))\n            .wait_for_newline(true)\n            .default(false)\n            .show_default(true)\n            .interact()\n    })\n    .await\n    .expect(\"Confirm thread panicked\");\n    match decision_result {\n        Ok(decision) => {\n            guard.disarmed = true;\n            decision\n        }\n        Err(dialoguer::Error::IO(err)) if err.kind() == io::ErrorKind::Interrupted => {\n            // Sometimes CTRL + C causes this error to be returned\n            mem::drop(guard);\n            false\n        }\n        Err(err) => {\n            mem::drop(guard);\n            panic!(\"Confirm dialog failed with {err}\")\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-cli/src/lib.rs",
    "content": "//! # SQLx CLI\n//!\n//! Command-line utility for the [SQLx](https://github.com/launchbadge/sqlx) ecosystem.\n//!\n//! This crate provides the core logic for the `sqlx` command-line interface, enabling database management,\n//! migrations, and offline query preparation for Rust projects using SQLx.\n//!\n//! ### Note: Semver Exempt API\n//! The API of this crate is not meant for general use and does *not* follow Semantic Versioning.\n//! The only crate that follows Semantic Versioning in the project is the `sqlx` crate itself.\n//! If you are building a custom SQLx driver, you should pin an exact version for `sqlx-cli` to\n//! avoid breakages:\n//!\n//! ```toml\n//! sqlx-cli = { version = \"=0.9.0\" }\n//! ```\n//!\n//! And then make releases in lockstep with `sqlx-cli`. We recommend all driver crates, in-tree\n//! or otherwise, use the same version numbers as `sqlx-cli` to avoid confusion.\n\nuse std::future::Future;\nuse std::io;\nuse std::time::Duration;\n\nuse futures_util::TryFutureExt;\n\nuse sqlx::AnyConnection;\nuse tokio::{select, signal};\n\nuse crate::opt::{Command, ConnectOpts, DatabaseCommand, MigrateCommand};\n\npub mod database;\npub mod metadata;\n// mod migration;\n// mod migrator;\n#[cfg(feature = \"completions\")]\npub mod completions;\npub mod migrate;\npub mod opt;\npub mod prepare;\n\npub use crate::opt::Opt;\n\npub use sqlx::_unstable::config::{self, Config};\n\n/// Check arguments for `--no-dotenv` _before_ Clap parsing, and apply `.env` if not set.\npub fn maybe_apply_dotenv() {\n    if std::env::args().any(|arg| arg == \"--no-dotenv\") {\n        return;\n    }\n\n    if let Err(e) = dotenvy::dotenv() {\n        if !e.not_found() {\n            eprintln!(\"Warning: error loading `.env` file: {e:?}\");\n        }\n    }\n}\n\npub async fn run(opt: Opt) -> anyhow::Result<()> {\n    // This `select!` is here so that when the process receives a `SIGINT` (CTRL + C),\n    // the futures currently running on this task get dropped before the program exits.\n    // This is currently necessary for the consumers of the `dialoguer` crate to restore\n    // the user's terminal if the process is interrupted while a dialog is being displayed.\n\n    let ctrlc_fut = signal::ctrl_c();\n    let do_run_fut = do_run(opt);\n\n    select! {\n        biased;\n        _ = ctrlc_fut => {\n            Ok(())\n        },\n        do_run_outcome = do_run_fut => {\n            do_run_outcome\n        }\n    }\n}\n\nasync fn do_run(opt: Opt) -> anyhow::Result<()> {\n    match opt.command {\n        Command::Migrate(migrate) => match migrate.command {\n            MigrateCommand::Add(opts) => migrate::add(opts).await?,\n            MigrateCommand::Run {\n                source,\n                config,\n                dry_run,\n                ignore_missing,\n                mut connect_opts,\n                target_version,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n\n                migrate::run(\n                    &config,\n                    &source,\n                    &connect_opts,\n                    dry_run,\n                    *ignore_missing,\n                    target_version,\n                )\n                .await?\n            }\n            MigrateCommand::Revert {\n                source,\n                config,\n                dry_run,\n                ignore_missing,\n                mut connect_opts,\n                target_version,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n\n                migrate::revert(\n                    &config,\n                    &source,\n                    &connect_opts,\n                    dry_run,\n                    *ignore_missing,\n                    target_version,\n                )\n                .await?\n            }\n            MigrateCommand::Info {\n                source,\n                config,\n                mut connect_opts,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n\n                migrate::info(&config, &source, &connect_opts).await?\n            }\n            MigrateCommand::BuildScript {\n                source,\n                config,\n                force,\n            } => {\n                let config = config.load_config().await?;\n\n                migrate::build_script(&config, &source, force)?\n            }\n        },\n\n        Command::Database(database) => match database.command {\n            DatabaseCommand::Create {\n                config,\n                mut connect_opts,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n                database::create(&connect_opts).await?\n            }\n            DatabaseCommand::Drop {\n                confirmation,\n                config,\n                mut connect_opts,\n                force,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n                database::drop(&connect_opts, !confirmation.yes, force).await?\n            }\n            DatabaseCommand::Reset {\n                confirmation,\n                source,\n                config,\n                mut connect_opts,\n                force,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n                database::reset(&config, &source, &connect_opts, !confirmation.yes, force).await?\n            }\n            DatabaseCommand::Setup {\n                source,\n                config,\n                mut connect_opts,\n            } => {\n                let config = config.load_config().await?;\n\n                connect_opts.populate_db_url(&config)?;\n                database::setup(&config, &source, &connect_opts).await?\n            }\n        },\n\n        Command::Prepare {\n            check,\n            all,\n            workspace,\n            mut connect_opts,\n            args,\n            config,\n        } => {\n            let config = config.load_config().await?;\n            connect_opts.populate_db_url(&config)?;\n            prepare::run(&config, check, all, workspace, connect_opts, args).await?\n        }\n\n        #[cfg(feature = \"completions\")]\n        Command::Completions { shell } => completions::run(shell),\n    };\n\n    Ok(())\n}\n\n/// Attempt to connect to the database server, retrying up to `ops.connect_timeout`.\nasync fn connect(config: &Config, opts: &ConnectOpts) -> anyhow::Result<AnyConnection> {\n    retry_connect_errors(opts, move |url| {\n        AnyConnection::connect_with_driver_config(url, &config.drivers)\n    })\n    .await\n}\n\n/// Attempt an operation that may return errors like `ConnectionRefused`,\n/// retrying up until `ops.connect_timeout`.\n///\n/// The closure is passed `&ops.database_url` for easy composition.\nasync fn retry_connect_errors<'a, F, Fut, T>(\n    opts: &'a ConnectOpts,\n    mut connect: F,\n) -> anyhow::Result<T>\nwhere\n    F: FnMut(&'a str) -> Fut,\n    Fut: Future<Output = sqlx::Result<T>> + 'a,\n{\n    let db_url = opts.expect_db_url()?;\n\n    backoff::future::retry(\n        backoff::ExponentialBackoffBuilder::new()\n            .with_max_elapsed_time(Some(Duration::from_secs(opts.connect_timeout)))\n            .build(),\n        || {\n            connect(db_url).map_err(|e| -> backoff::Error<anyhow::Error> {\n                if let sqlx::Error::Io(ref ioe) = e {\n                    match ioe.kind() {\n                        io::ErrorKind::ConnectionRefused\n                        | io::ErrorKind::ConnectionReset\n                        | io::ErrorKind::ConnectionAborted => {\n                            return backoff::Error::transient(e.into());\n                        }\n                        _ => (),\n                    }\n                }\n\n                backoff::Error::permanent(e.into())\n            })\n        },\n    )\n    .await\n}\n"
  },
  {
    "path": "sqlx-cli/src/metadata.rs",
    "content": "use std::{\n    collections::{btree_map, BTreeMap, BTreeSet},\n    ffi::OsStr,\n    path::{Path, PathBuf},\n    process::Command,\n    str::FromStr,\n};\n\nuse anyhow::Context;\nuse cargo_metadata::{\n    Metadata as CargoMetadata, Package as MetadataPackage, PackageId as MetadataId,\n};\n\n/// The minimal amount of package information we care about\n///\n/// The package's `name` is used to `cargo clean -p` specific crates while the `src_paths` are\n/// are used to trigger recompiles of packages within the workspace\n#[derive(Debug)]\npub struct Package {\n    name: String,\n    src_paths: Vec<PathBuf>,\n}\n\nimpl Package {\n    pub fn name(&self) -> &str {\n        &self.name\n    }\n\n    pub fn src_paths(&self) -> &[PathBuf] {\n        &self.src_paths\n    }\n}\n\nimpl From<&MetadataPackage> for Package {\n    fn from(package: &MetadataPackage) -> Self {\n        let name = package.name.clone();\n        let src_paths = package\n            .targets\n            .iter()\n            .map(|target| target.src_path.clone().into_std_path_buf())\n            .collect();\n\n        Self { name, src_paths }\n    }\n}\n\n/// Contains metadata for the current project\npub struct Metadata {\n    /// Maps packages metadata id to the package\n    ///\n    /// Currently `MetadataId` is used over `PkgId` because pkgid is not a UUID\n    packages: BTreeMap<MetadataId, Package>,\n    /// All of the crates in the current workspace\n    workspace_members: Vec<MetadataId>,\n    /// Workspace root path.\n    workspace_root: PathBuf,\n    /// Maps each dependency to its set of dependents\n    reverse_deps: BTreeMap<MetadataId, BTreeSet<MetadataId>>,\n    /// The target directory of the project\n    ///\n    /// Typically `target` at the workspace root, but can be overridden\n    target_directory: PathBuf,\n    /// Crate in the current working directory, empty if run from a\n    /// virtual workspace root.\n    current_package: Option<Package>,\n}\n\nimpl Metadata {\n    /// Parse the manifest from the current working directory using `cargo metadata`.\n    pub fn from_current_directory(cargo: &OsStr) -> anyhow::Result<Self> {\n        let output = Command::new(cargo)\n            .args([\"metadata\", \"--format-version=1\"])\n            .output()\n            .context(\"Could not fetch metadata\")?;\n\n        std::str::from_utf8(&output.stdout)\n            .context(\"Invalid `cargo metadata` output\")?\n            .parse()\n            .context(\"Issue parsing `cargo metadata` output - consider manually running it to check for issues\")\n    }\n\n    pub fn package(&self, id: &MetadataId) -> Option<&Package> {\n        self.packages.get(id)\n    }\n\n    pub fn entries(&self) -> btree_map::Iter<'_, MetadataId, Package> {\n        self.packages.iter()\n    }\n\n    pub fn workspace_members(&self) -> &[MetadataId] {\n        &self.workspace_members\n    }\n\n    pub fn workspace_root(&self) -> &Path {\n        &self.workspace_root\n    }\n\n    pub fn target_directory(&self) -> &Path {\n        &self.target_directory\n    }\n\n    pub fn current_package(&self) -> Option<&Package> {\n        self.current_package.as_ref()\n    }\n\n    /// Gets all dependents (direct and transitive) of `id`\n    pub fn all_dependents_of(&self, id: &MetadataId) -> BTreeSet<&MetadataId> {\n        let mut dependents = BTreeSet::new();\n        self.all_dependents_of_helper(id, &mut dependents);\n        dependents\n    }\n\n    fn all_dependents_of_helper<'this>(\n        &'this self,\n        id: &MetadataId,\n        dependents: &mut BTreeSet<&'this MetadataId>,\n    ) {\n        if let Some(immediate_dependents) = self.reverse_deps.get(id) {\n            for immediate_dependent in immediate_dependents {\n                if dependents.insert(immediate_dependent) {\n                    self.all_dependents_of_helper(immediate_dependent, dependents);\n                }\n            }\n        }\n    }\n}\n\nimpl FromStr for Metadata {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let cargo_metadata: CargoMetadata = serde_json::from_str(s)?;\n\n        // Extract the package in the current working directory, empty if run from a\n        // virtual workspace root.\n        let current_package: Option<Package> = cargo_metadata.root_package().map(Package::from);\n\n        let CargoMetadata {\n            packages: metadata_packages,\n            workspace_members,\n            workspace_root,\n            resolve,\n            target_directory,\n            ..\n        } = cargo_metadata;\n\n        let mut packages = BTreeMap::new();\n        for metadata_package in metadata_packages {\n            let package = Package::from(&metadata_package);\n            packages.insert(metadata_package.id, package);\n        }\n\n        let mut reverse_deps: BTreeMap<_, BTreeSet<_>> = BTreeMap::new();\n        let resolve =\n            resolve.context(\"Resolving the dependency graph failed (old version of cargo)\")?;\n        for node in resolve.nodes {\n            for dep in node.deps {\n                let dependent = node.id.clone();\n                let dependency = dep.pkg;\n                reverse_deps\n                    .entry(dependency)\n                    .or_default()\n                    .insert(dependent);\n            }\n        }\n\n        let workspace_root = workspace_root.into_std_path_buf();\n        let target_directory = target_directory.into_std_path_buf();\n\n        Ok(Self {\n            packages,\n            workspace_members,\n            workspace_root,\n            reverse_deps,\n            target_directory,\n            current_package,\n        })\n    }\n}\n\n/// The absolute path to the directory containing the `Cargo.toml` manifest.\n/// Depends on the current working directory.\npub(crate) fn manifest_dir(cargo: &OsStr) -> anyhow::Result<PathBuf> {\n    let stdout = Command::new(cargo)\n        .args([\"locate-project\", \"--message-format=plain\"])\n        .output()\n        .context(\"could not locate manifest directory\")?\n        .stdout;\n\n    let mut manifest_path: PathBuf = std::str::from_utf8(&stdout)\n        .context(\"output of `cargo locate-project` was not valid UTF-8\")?\n        // remove trailing newline\n        .trim()\n        .into();\n\n    manifest_path.pop();\n    Ok(manifest_path)\n}\n"
  },
  {
    "path": "sqlx-cli/src/migrate.rs",
    "content": "use crate::config::Config;\nuse crate::opt::{AddMigrationOpts, ConnectOpts, MigrationSourceOpt};\nuse anyhow::{bail, Context};\nuse console::style;\nuse sqlx::migrate::{AppliedMigration, Migrate, MigrateError, MigrationType, Migrator};\nuse sqlx::Connection;\nuse std::borrow::Cow;\nuse std::collections::{HashMap, HashSet};\nuse std::fmt::Write;\nuse std::fs::{self, File};\nuse std::path::Path;\nuse std::time::Duration;\n\npub async fn add(opts: AddMigrationOpts) -> anyhow::Result<()> {\n    let config = opts.config.load_config().await?;\n\n    let source = opts.source.resolve_path(&config);\n\n    fs::create_dir_all(source).context(\"Unable to create migrations directory\")?;\n\n    let migrator = opts.source.resolve(&config).await?;\n\n    let version_prefix = opts.version_prefix(&config, &migrator);\n\n    if opts.reversible(&config, &migrator) {\n        create_file(\n            source,\n            &version_prefix,\n            &opts.description,\n            MigrationType::ReversibleUp,\n        )?;\n        create_file(\n            source,\n            &version_prefix,\n            &opts.description,\n            MigrationType::ReversibleDown,\n        )?;\n    } else {\n        create_file(\n            source,\n            &version_prefix,\n            &opts.description,\n            MigrationType::Simple,\n        )?;\n    }\n\n    // if the migrations directory is empty\n    let has_existing_migrations = fs::read_dir(source)\n        .map(|mut dir| dir.next().is_some())\n        .unwrap_or(false);\n\n    if !has_existing_migrations {\n        let quoted_source = if opts.source.source.is_some() {\n            format!(\"{source:?}\")\n        } else {\n            \"\".to_string()\n        };\n\n        // Provide a link to the current version in case the details change.\n        // Patch version is deliberately omitted.\n        let version = if let (Some(major), Some(minor)) = (\n            // Don't fail if we're not being built by Cargo\n            option_env!(\"CARGO_PKG_VERSION_MAJOR\"),\n            option_env!(\"CARGO_PKG_VERSION_MINOR\"),\n        ) {\n            format!(\"{major}.{minor}\")\n        } else {\n            // If a version isn't available, \"latest\" is fine.\n            \"latest\".to_string()\n        };\n\n        print!(\n            r#\"\nCongratulations on creating your first migration!\n\nDid you know you can embed your migrations in your application binary?\nOn startup, after creating your database connection or pool, add:\n\nsqlx::migrate!({quoted_source}).run(<&your_pool OR &mut your_connection>).await?;\n\nNote that the compiler won't pick up new migrations if no Rust source files have changed.\nYou can create a Cargo build script to work around this with `sqlx migrate build-script`.\n\nSee: https://docs.rs/sqlx/{version}/sqlx/macro.migrate.html\n\"#,\n        );\n    }\n\n    Ok(())\n}\n\nfn create_file(\n    migration_source: &str,\n    file_prefix: &str,\n    description: &str,\n    migration_type: MigrationType,\n) -> anyhow::Result<()> {\n    use std::path::PathBuf;\n\n    let mut file_name = file_prefix.to_string();\n    file_name.push('_');\n    file_name.push_str(&description.replace(' ', \"_\"));\n    file_name.push_str(migration_type.suffix());\n\n    let mut path = PathBuf::new();\n    path.push(migration_source);\n    path.push(&file_name);\n\n    println!(\"Creating {}\", style(path.display()).cyan());\n\n    let mut file = File::create(&path).context(\"Failed to create migration file\")?;\n\n    std::io::Write::write_all(&mut file, migration_type.file_content().as_bytes())?;\n\n    Ok(())\n}\n\nfn short_checksum(checksum: &[u8]) -> String {\n    let mut s = String::with_capacity(checksum.len() * 2);\n    for b in checksum {\n        write!(&mut s, \"{b:02x?}\").expect(\"should not fail to write to str\");\n    }\n    s\n}\n\npub async fn info(\n    config: &Config,\n    migration_source: &MigrationSourceOpt,\n    connect_opts: &ConnectOpts,\n) -> anyhow::Result<()> {\n    let migrator = migration_source.resolve(config).await?;\n\n    let mut conn = crate::connect(config, connect_opts).await?;\n\n    // FIXME: we shouldn't actually be creating anything here\n    for schema_name in &config.migrate.create_schemas {\n        conn.create_schema_if_not_exists(schema_name).await?;\n    }\n\n    conn.ensure_migrations_table(config.migrate.table_name())\n        .await?;\n\n    let applied_migrations: HashMap<_, _> = conn\n        .list_applied_migrations(config.migrate.table_name())\n        .await?\n        .into_iter()\n        .map(|m| (m.version, m))\n        .collect();\n\n    for migration in migrator.iter() {\n        if migration.migration_type.is_down_migration() {\n            // Skipping down migrations\n            continue;\n        }\n\n        let applied = applied_migrations.get(&migration.version);\n\n        let (status_msg, mismatched_checksum) = if let Some(applied) = applied {\n            if applied.checksum != migration.checksum {\n                (style(\"installed (different checksum)\").red(), true)\n            } else {\n                (style(\"installed\").green(), false)\n            }\n        } else {\n            (style(\"pending\").yellow(), false)\n        };\n\n        println!(\n            \"{}/{} {}\",\n            style(migration.version).cyan(),\n            status_msg,\n            migration.description\n        );\n\n        if mismatched_checksum {\n            println!(\n                \"applied migration had checksum {}\",\n                short_checksum(\n                    &applied\n                        .map(|a| a.checksum.clone())\n                        .unwrap_or_else(|| Cow::Owned(vec![]))\n                ),\n            );\n            println!(\n                \"local migration has checksum {}\",\n                short_checksum(&migration.checksum)\n            )\n        }\n    }\n\n    let _ = conn.close().await;\n\n    Ok(())\n}\n\nfn validate_applied_migrations(\n    applied_migrations: &[AppliedMigration],\n    migrator: &Migrator,\n    ignore_missing: bool,\n) -> Result<(), MigrateError> {\n    if ignore_missing {\n        return Ok(());\n    }\n\n    let migrations: HashSet<_> = migrator.iter().map(|m| m.version).collect();\n\n    for applied_migration in applied_migrations {\n        if !migrations.contains(&applied_migration.version) {\n            return Err(MigrateError::VersionMissing(applied_migration.version));\n        }\n    }\n\n    Ok(())\n}\n\npub async fn run(\n    config: &Config,\n    migration_source: &MigrationSourceOpt,\n    connect_opts: &ConnectOpts,\n    dry_run: bool,\n    ignore_missing: bool,\n    target_version: Option<i64>,\n) -> anyhow::Result<()> {\n    let migrator = migration_source.resolve(config).await?;\n\n    if let Some(target_version) = target_version {\n        if !migrator.version_exists(target_version) {\n            bail!(MigrateError::VersionNotPresent(target_version));\n        }\n    }\n\n    let mut conn = crate::connect(config, connect_opts).await?;\n\n    for schema_name in &config.migrate.create_schemas {\n        conn.create_schema_if_not_exists(schema_name).await?;\n    }\n\n    conn.ensure_migrations_table(config.migrate.table_name())\n        .await?;\n\n    let version = conn.dirty_version(config.migrate.table_name()).await?;\n    if let Some(version) = version {\n        bail!(MigrateError::Dirty(version));\n    }\n\n    let applied_migrations = conn\n        .list_applied_migrations(config.migrate.table_name())\n        .await?;\n    validate_applied_migrations(&applied_migrations, &migrator, ignore_missing)?;\n\n    let latest_version = applied_migrations\n        .iter()\n        .max_by(|x, y| x.version.cmp(&y.version))\n        .map(|migration| migration.version)\n        .unwrap_or(0);\n    if let Some(target_version) = target_version {\n        if target_version < latest_version {\n            bail!(MigrateError::VersionTooOld(target_version, latest_version));\n        }\n    }\n\n    let applied_migrations: HashMap<_, _> = applied_migrations\n        .into_iter()\n        .map(|m| (m.version, m))\n        .collect();\n\n    for migration in migrator.iter() {\n        if migration.migration_type.is_down_migration() {\n            // Skipping down migrations\n            continue;\n        }\n\n        match applied_migrations.get(&migration.version) {\n            Some(applied_migration) => {\n                if migration.checksum != applied_migration.checksum {\n                    bail!(MigrateError::VersionMismatch(migration.version));\n                }\n            }\n            None => {\n                let skip =\n                    target_version.is_some_and(|target_version| migration.version > target_version);\n\n                let elapsed = if dry_run || skip {\n                    Duration::new(0, 0)\n                } else {\n                    conn.apply(config.migrate.table_name(), migration).await?\n                };\n                let text = if skip {\n                    \"Skipped\"\n                } else if dry_run {\n                    \"Can apply\"\n                } else {\n                    \"Applied\"\n                };\n\n                println!(\n                    \"{} {}/{} {} {}\",\n                    text,\n                    style(migration.version).cyan(),\n                    style(migration.migration_type.label()).green(),\n                    migration.description,\n                    style(format!(\"({elapsed:?})\")).dim()\n                );\n            }\n        }\n    }\n\n    // Close the connection before exiting:\n    // * For MySQL and Postgres this should ensure timely cleanup on the server side,\n    //   including decrementing the open connection count.\n    // * For SQLite this should checkpoint and delete the WAL file to ensure the migrations\n    //   were actually applied to the database file and aren't just sitting in the WAL file.\n    let _ = conn.close().await;\n\n    Ok(())\n}\n\npub async fn revert(\n    config: &Config,\n    migration_source: &MigrationSourceOpt,\n    connect_opts: &ConnectOpts,\n    dry_run: bool,\n    ignore_missing: bool,\n    target_version: Option<i64>,\n) -> anyhow::Result<()> {\n    let migrator = migration_source.resolve(config).await?;\n\n    if let Some(target_version) = target_version {\n        if target_version != 0 && !migrator.version_exists(target_version) {\n            bail!(MigrateError::VersionNotPresent(target_version));\n        }\n    }\n\n    let mut conn = crate::connect(config, connect_opts).await?;\n\n    // FIXME: we should not be creating anything here if it doesn't exist\n    for schema_name in &config.migrate.create_schemas {\n        conn.create_schema_if_not_exists(schema_name).await?;\n    }\n\n    conn.ensure_migrations_table(config.migrate.table_name())\n        .await?;\n\n    let version = conn.dirty_version(config.migrate.table_name()).await?;\n    if let Some(version) = version {\n        bail!(MigrateError::Dirty(version));\n    }\n\n    let applied_migrations = conn\n        .list_applied_migrations(config.migrate.table_name())\n        .await?;\n    validate_applied_migrations(&applied_migrations, &migrator, ignore_missing)?;\n\n    let latest_version = applied_migrations\n        .iter()\n        .max_by(|x, y| x.version.cmp(&y.version))\n        .map(|migration| migration.version)\n        .unwrap_or(0);\n    if let Some(target_version) = target_version {\n        if target_version > latest_version {\n            bail!(MigrateError::VersionTooNew(target_version, latest_version));\n        }\n    }\n\n    let applied_migrations: HashMap<_, _> = applied_migrations\n        .into_iter()\n        .map(|m| (m.version, m))\n        .collect();\n\n    let mut is_applied = false;\n    for migration in migrator.iter().rev() {\n        if !migration.migration_type.is_down_migration() {\n            // Skipping non down migration\n            // This will skip any simple or up migration file\n            continue;\n        }\n\n        if applied_migrations.contains_key(&migration.version) {\n            let skip =\n                target_version.is_some_and(|target_version| migration.version <= target_version);\n\n            let elapsed = if dry_run || skip {\n                Duration::new(0, 0)\n            } else {\n                conn.revert(config.migrate.table_name(), migration).await?\n            };\n            let text = if skip {\n                \"Skipped\"\n            } else if dry_run {\n                \"Can apply\"\n            } else {\n                \"Applied\"\n            };\n\n            println!(\n                \"{} {}/{} {} {}\",\n                text,\n                style(migration.version).cyan(),\n                style(migration.migration_type.label()).green(),\n                migration.description,\n                style(format!(\"({elapsed:?})\")).dim()\n            );\n\n            is_applied = true;\n\n            // Only a single migration will be reverted at a time if no target\n            // version is supplied, so we break.\n            if target_version.is_none() {\n                break;\n            }\n        }\n    }\n    if !is_applied {\n        println!(\"No migrations available to revert\");\n    }\n\n    let _ = conn.close().await;\n\n    Ok(())\n}\n\npub fn build_script(\n    config: &Config,\n    migration_source: &MigrationSourceOpt,\n    force: bool,\n) -> anyhow::Result<()> {\n    let source = migration_source.resolve_path(config);\n\n    anyhow::ensure!(\n        Path::new(\"Cargo.toml\").exists(),\n        \"must be run in a Cargo project root\"\n    );\n\n    anyhow::ensure!(\n        (force || !Path::new(\"build.rs\").exists()),\n        \"build.rs already exists; use --force to overwrite\"\n    );\n\n    let contents = format!(\n        r#\"// generated by `sqlx migrate build-script`\nfn main() {{\n    // trigger recompilation when a new migration is added\n    println!(\"cargo:rerun-if-changed={source}\");\n}}\n\"#,\n    );\n\n    fs::write(\"build.rs\", contents)?;\n\n    println!(\"Created `build.rs`; be sure to check it into version control!\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-cli/src/opt.rs",
    "content": "use crate::config::migrate::{DefaultMigrationType, DefaultVersioning};\nuse crate::config::Config;\nuse anyhow::Context;\nuse chrono::Utc;\nuse clap::{\n    builder::{styling::AnsiColor, Styles},\n    Args, Parser,\n};\n#[cfg(feature = \"completions\")]\nuse clap_complete::Shell;\nuse sqlx::migrate::{MigrateError, Migrator, ResolveWith};\nuse std::env;\nuse std::ops::{Deref, Not};\nuse std::path::PathBuf;\n\nconst HELP_STYLES: Styles = Styles::styled()\n    .header(AnsiColor::Blue.on_default().bold())\n    .usage(AnsiColor::Blue.on_default().bold())\n    .literal(AnsiColor::White.on_default())\n    .placeholder(AnsiColor::Green.on_default());\n\n#[derive(Parser, Debug)]\n#[clap(version, about, author, styles = HELP_STYLES)]\npub struct Opt {\n    // https://github.com/launchbadge/sqlx/pull/3724 placed this here,\n    // but the intuitive place would be in the arguments for each subcommand.\n    #[clap(flatten)]\n    pub no_dotenv: NoDotenvOpt,\n\n    #[clap(subcommand)]\n    pub command: Command,\n}\n\n#[derive(Parser, Debug)]\npub enum Command {\n    #[clap(alias = \"db\")]\n    Database(DatabaseOpt),\n\n    /// Generate query metadata to support offline compile-time verification.\n    ///\n    /// Saves metadata for all invocations of `query!` and related macros to a `.sqlx` directory\n    /// in the current directory (or workspace root with `--workspace`), overwriting if needed.\n    ///\n    /// During project compilation, the absence of the `DATABASE_URL` environment variable or\n    /// the presence of `SQLX_OFFLINE` (with a value of `true` or `1`) will constrain the\n    /// compile-time verification to only read from the cached query metadata.\n    #[clap(alias = \"prep\")]\n    Prepare {\n        /// Run in 'check' mode. Exits with 0 if the query metadata is up-to-date. Exits with\n        /// 1 if the query metadata needs updating.\n        #[clap(long)]\n        check: bool,\n\n        /// Prepare query macros in dependencies that exist outside the current crate or workspace.\n        #[clap(long)]\n        all: bool,\n\n        /// Generate a single workspace-level `.sqlx` folder.\n        ///\n        /// This option is intended for workspaces where multiple crates use SQLx. If there is only\n        /// one, it is better to run `cargo sqlx prepare` without this option inside that crate.\n        #[clap(long)]\n        workspace: bool,\n\n        /// Arguments to be passed to `cargo rustc ...`.\n        #[clap(last = true)]\n        args: Vec<String>,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n    },\n\n    #[clap(alias = \"mig\")]\n    Migrate(MigrateOpt),\n\n    #[cfg(feature = \"completions\")]\n    /// Generate shell completions for the specified shell\n    Completions { shell: Shell },\n}\n\n/// Group of commands for creating and dropping your database.\n#[derive(Parser, Debug)]\npub struct DatabaseOpt {\n    #[clap(subcommand)]\n    pub command: DatabaseCommand,\n}\n\n#[derive(Parser, Debug)]\npub enum DatabaseCommand {\n    /// Creates the database specified in your DATABASE_URL.\n    Create {\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n    },\n\n    /// Drops the database specified in your DATABASE_URL.\n    Drop {\n        #[clap(flatten)]\n        confirmation: Confirmation,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n\n        /// PostgreSQL only: force drops the database.\n        #[clap(long, short, default_value = \"false\")]\n        force: bool,\n    },\n\n    /// Drops the database specified in your DATABASE_URL, re-creates it, and runs any pending migrations.\n    Reset {\n        #[clap(flatten)]\n        confirmation: Confirmation,\n\n        #[clap(flatten)]\n        source: MigrationSourceOpt,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n\n        /// PostgreSQL only: force drops the database.\n        #[clap(long, short, default_value = \"false\")]\n        force: bool,\n    },\n\n    /// Creates the database specified in your DATABASE_URL and runs any pending migrations.\n    Setup {\n        #[clap(flatten)]\n        source: MigrationSourceOpt,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n    },\n}\n\n/// Group of commands for creating and running migrations.\n#[derive(Parser, Debug)]\npub struct MigrateOpt {\n    #[clap(subcommand)]\n    pub command: MigrateCommand,\n}\n\n#[derive(Parser, Debug)]\npub enum MigrateCommand {\n    /// Create a new migration with the given description.\n    ///\n    /// --------------------------------\n    ///\n    /// Migrations may either be simple, or reversible.\n    ///\n    /// Reversible migrations can be reverted with `sqlx migrate revert`, simple migrations cannot.\n    ///\n    /// Reversible migrations are created as a pair of two files with the same filename but\n    /// extensions `.up.sql` and `.down.sql` for the up-migration and down-migration, respectively.\n    ///\n    /// The up-migration should contain the commands to be used when applying the migration,\n    /// while the down-migration should contain the commands to reverse the changes made by the\n    /// up-migration.\n    ///\n    /// When writing down-migrations, care should be taken to ensure that they\n    /// do not leave the database in an inconsistent state.\n    ///\n    /// Simple migrations have just `.sql` for their extension and represent an up-migration only.\n    ///\n    /// Note that reverting a migration is **destructive** and will likely result in data loss.\n    /// Reverting a migration will not restore any data discarded by commands in the up-migration.\n    ///\n    /// It is recommended to always back up the database before running migrations.\n    ///\n    /// --------------------------------\n    ///\n    /// For convenience, this command attempts to detect if reversible migrations are in-use.\n    ///\n    /// If the latest existing migration is reversible, the new migration will also be reversible.\n    ///\n    /// Otherwise, a simple migration is created.\n    ///\n    /// This behavior can be overridden by `--simple` or `--reversible`, respectively.\n    ///\n    /// The default type to use can also be set in `sqlx.toml`.\n    ///\n    /// --------------------------------\n    ///\n    /// A version number will be automatically assigned to the migration.\n    ///\n    /// Migrations are applied in ascending order by version number.\n    /// Version numbers do not need to be strictly consecutive.\n    ///\n    /// The migration process will abort if SQLx encounters a migration with a version number\n    /// less than _any_ previously applied migration.\n    ///\n    /// Migrations should only be created with increasing version number.\n    ///\n    /// --------------------------------\n    ///\n    /// For convenience, this command will attempt to detect if sequential versioning is in use,\n    /// and if so, continue the sequence.\n    ///\n    /// Sequential versioning is inferred if:\n    ///\n    /// * The version numbers of the last two migrations differ by exactly 1, or:\n    ///\n    /// * only one migration exists and its version number is either 0 or 1.\n    ///\n    /// Otherwise, timestamp versioning (`YYYYMMDDHHMMSS`) is assumed.\n    ///\n    /// This behavior can be overridden by `--timestamp` or `--sequential`, respectively.\n    ///\n    /// The default versioning to use can also be set in `sqlx.toml`.\n    Add(AddMigrationOpts),\n\n    /// Run all pending migrations.\n    Run {\n        #[clap(flatten)]\n        source: MigrationSourceOpt,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        /// List all the migrations to be run without applying\n        #[clap(long)]\n        dry_run: bool,\n\n        #[clap(flatten)]\n        ignore_missing: IgnoreMissing,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n\n        /// Apply migrations up to the specified version. If unspecified, apply all\n        /// pending migrations. If already at the target version, then no-op.\n        #[clap(long)]\n        target_version: Option<i64>,\n    },\n\n    /// Revert the latest migration with a down file.\n    Revert {\n        #[clap(flatten)]\n        source: MigrationSourceOpt,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        /// List the migration to be reverted without applying\n        #[clap(long)]\n        dry_run: bool,\n\n        #[clap(flatten)]\n        ignore_missing: IgnoreMissing,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n\n        /// Revert migrations down to the specified version. If unspecified, revert\n        /// only the last migration. Set to 0 to revert all migrations. If already\n        /// at the target version, then no-op.\n        #[clap(long)]\n        target_version: Option<i64>,\n    },\n\n    /// List all available migrations.\n    Info {\n        #[clap(flatten)]\n        source: MigrationSourceOpt,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        #[clap(flatten)]\n        connect_opts: ConnectOpts,\n    },\n\n    /// Generate a `build.rs` to trigger recompilation when a new migration is added.\n    ///\n    /// Must be run in a Cargo project root.\n    BuildScript {\n        #[clap(flatten)]\n        source: MigrationSourceOpt,\n\n        #[clap(flatten)]\n        config: ConfigOpt,\n\n        /// Overwrite the build script if it already exists.\n        #[clap(long)]\n        force: bool,\n    },\n}\n\n#[derive(Args, Debug)]\npub struct AddMigrationOpts {\n    pub description: String,\n\n    #[clap(flatten)]\n    pub source: MigrationSourceOpt,\n\n    #[clap(flatten)]\n    pub config: ConfigOpt,\n\n    /// If set, create an up-migration only. Conflicts with `--reversible`.\n    #[clap(long, conflicts_with = \"reversible\")]\n    simple: bool,\n\n    /// If set, create a pair of up and down migration files with same version.\n    ///\n    /// Conflicts with `--simple`.\n    #[clap(short, long, conflicts_with = \"simple\")]\n    reversible: bool,\n\n    /// If set, use timestamp versioning for the new migration. Conflicts with `--sequential`.\n    ///\n    /// Timestamp format: `YYYYMMDDHHMMSS`\n    #[clap(short, long, conflicts_with = \"sequential\")]\n    timestamp: bool,\n\n    /// If set, use sequential versioning for the new migration. Conflicts with `--timestamp`.\n    #[clap(short, long, conflicts_with = \"timestamp\")]\n    sequential: bool,\n}\n\n/// Argument for the migration scripts source.\n#[derive(Args, Debug)]\npub struct MigrationSourceOpt {\n    /// Path to folder containing migrations.\n    ///\n    /// Defaults to `migrations/` if not specified, but a different default may be set by `sqlx.toml`.\n    #[clap(long)]\n    pub source: Option<String>,\n}\n\nimpl MigrationSourceOpt {\n    pub fn resolve_path<'a>(&'a self, config: &'a Config) -> &'a str {\n        if let Some(source) = &self.source {\n            return source;\n        }\n\n        config.migrate.migrations_dir()\n    }\n\n    pub async fn resolve(&self, config: &Config) -> Result<Migrator, MigrateError> {\n        Migrator::new(ResolveWith(\n            self.resolve_path(config),\n            config.migrate.to_resolve_config(),\n        ))\n        .await\n    }\n}\n\n/// Argument for the database URL.\n#[derive(Args, Debug)]\npub struct ConnectOpts {\n    #[clap(flatten)]\n    pub no_dotenv: NoDotenvOpt,\n\n    /// Location of the DB, by default will be read from the DATABASE_URL env var or `.env` files.\n    #[clap(long, short = 'D')]\n    pub database_url: Option<String>,\n\n    /// The maximum time, in seconds, to try connecting to the database server before\n    /// returning an error.\n    #[clap(long, default_value = \"10\")]\n    pub connect_timeout: u64,\n\n    /// Set whether or not to create SQLite databases in Write-Ahead Log (WAL) mode:\n    /// https://www.sqlite.org/wal.html\n    ///\n    /// WAL mode is enabled by default for SQLite databases created by `sqlx-cli`.\n    ///\n    /// However, if your application sets a `journal_mode` on `SqliteConnectOptions` to something\n    /// other than `Wal`, then it will have to take the database file out of WAL mode on connecting,\n    /// which requires an exclusive lock and may return a `database is locked` (`SQLITE_BUSY`) error.\n    #[cfg(feature = \"_sqlite\")]\n    #[clap(long, action = clap::ArgAction::Set, default_value = \"true\")]\n    pub sqlite_create_db_wal: bool,\n}\n\n#[derive(Args, Debug)]\npub struct NoDotenvOpt {\n    /// Do not automatically load `.env` files.\n    #[clap(long)]\n    // Parsing of this flag is actually handled _before_ calling Clap,\n    // by `crate::maybe_apply_dotenv()`.\n    #[allow(unused)] // TODO: switch to `#[expect]`\n    pub no_dotenv: bool,\n}\n\n#[derive(Args, Debug)]\npub struct ConfigOpt {\n    /// Override the path to the config file.\n    ///\n    /// Defaults to `sqlx.toml` in the current directory, if it exists.\n    ///\n    /// Configuration file loading may be bypassed with `--config=/dev/null` on Linux,\n    /// or `--config=NUL` on Windows.\n    ///\n    /// Config file loading is enabled by the `sqlx-toml` feature.\n    #[clap(long)]\n    pub config: Option<PathBuf>,\n}\n\nimpl ConnectOpts {\n    /// Require a database URL to be provided, otherwise\n    /// return an error.\n    pub fn expect_db_url(&self) -> anyhow::Result<&str> {\n        self.database_url\n            .as_deref()\n            .context(\"BUG: database_url not populated\")\n    }\n\n    /// Populate `database_url` from the environment, if not set.\n    pub fn populate_db_url(&mut self, config: &Config) -> anyhow::Result<()> {\n        if self.database_url.is_some() {\n            return Ok(());\n        }\n\n        let var = config.common.database_url_var();\n\n        let context = if var != \"DATABASE_URL\" {\n            \" (`common.database-url-var` in `sqlx.toml`)\"\n        } else {\n            \"\"\n        };\n\n        match env::var(var) {\n            Ok(url) => {\n                if !context.is_empty() {\n                    eprintln!(\"Read database url from `{var}`{context}\");\n                }\n\n                self.database_url = Some(url)\n            }\n            Err(env::VarError::NotPresent) => {\n                anyhow::bail!(\"`--database-url` or `{var}`{context} must be set\")\n            }\n            Err(env::VarError::NotUnicode(_)) => {\n                anyhow::bail!(\"`{var}`{context} is not valid UTF-8\");\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl ConfigOpt {\n    pub async fn load_config(&self) -> anyhow::Result<Config> {\n        let path = self.config.clone();\n\n        // Tokio does file I/O on a background task anyway\n        tokio::task::spawn_blocking(|| {\n            if let Some(path) = path {\n                let err_str = format!(\"error reading config from {path:?}\");\n                Config::try_from_path(path).context(err_str)\n            } else {\n                let path = PathBuf::from(\"sqlx.toml\");\n\n                if path.exists() {\n                    eprintln!(\"Found `sqlx.toml` in current directory; reading...\");\n                    Ok(Config::try_from_path(path)?)\n                } else {\n                    Ok(Config::default())\n                }\n            }\n        })\n        .await\n        .context(\"unexpected error loading config\")?\n    }\n}\n\n/// Argument for automatic confirmation.\n#[derive(Args, Copy, Clone, Debug)]\npub struct Confirmation {\n    /// Automatic confirmation. Without this option, you will be prompted before dropping\n    /// your database.\n    #[clap(short)]\n    pub yes: bool,\n}\n\n/// Argument for ignoring applied migrations that were not resolved.\n#[derive(Args, Copy, Clone, Debug)]\npub struct IgnoreMissing {\n    /// Ignore applied migrations that are missing in the resolved migrations\n    #[clap(long)]\n    ignore_missing: bool,\n}\n\nimpl Deref for IgnoreMissing {\n    type Target = bool;\n\n    fn deref(&self) -> &Self::Target {\n        &self.ignore_missing\n    }\n}\n\nimpl Not for IgnoreMissing {\n    type Output = bool;\n\n    fn not(self) -> Self::Output {\n        !self.ignore_missing\n    }\n}\n\nimpl AddMigrationOpts {\n    pub fn reversible(&self, config: &Config, migrator: &Migrator) -> bool {\n        if self.reversible {\n            return true;\n        }\n        if self.simple {\n            return false;\n        }\n\n        match config.migrate.defaults.migration_type {\n            DefaultMigrationType::Inferred => migrator\n                .iter()\n                .last()\n                .is_some_and(|m| m.migration_type.is_reversible()),\n            DefaultMigrationType::Simple => false,\n            DefaultMigrationType::Reversible => true,\n        }\n    }\n\n    pub fn version_prefix(&self, config: &Config, migrator: &Migrator) -> String {\n        let default_versioning = &config.migrate.defaults.migration_versioning;\n\n        match (self.timestamp, self.sequential, default_versioning) {\n            (true, false, _) | (false, false, DefaultVersioning::Timestamp) => next_timestamp(),\n            (false, true, _) | (false, false, DefaultVersioning::Sequential) => fmt_sequential(\n                migrator\n                    .migrations\n                    .last()\n                    .map_or(1, |migration| migration.version + 1),\n            ),\n            (false, false, DefaultVersioning::Inferred) => {\n                migrator\n                    .migrations\n                    .rchunks(2)\n                    .next()\n                    .and_then(|migrations| {\n                        match migrations {\n                            [previous, latest] => {\n                                // If the latest two versions differ by 1, infer sequential.\n                                (latest.version - previous.version == 1)\n                                    .then_some(latest.version + 1)\n                            }\n                            [latest] => {\n                                // If only one migration exists and its version is 0 or 1, infer sequential\n                                matches!(latest.version, 0 | 1).then_some(latest.version + 1)\n                            }\n                            _ => unreachable!(),\n                        }\n                    })\n                    .map_or_else(next_timestamp, fmt_sequential)\n            }\n            (true, true, _) => unreachable!(\"BUG: Clap should have rejected this case\"),\n        }\n    }\n}\n\nfn next_timestamp() -> String {\n    Utc::now().format(\"%Y%m%d%H%M%S\").to_string()\n}\n\nfn fmt_sequential(version: i64) -> String {\n    format!(\"{version:04}\")\n}\n"
  },
  {
    "path": "sqlx-cli/src/prepare.rs",
    "content": "use std::collections::{BTreeSet, HashSet};\nuse std::env;\nuse std::ffi::{OsStr, OsString};\nuse std::fs;\nuse std::path::{Path, PathBuf};\nuse std::process::Command;\n\nuse crate::metadata::{manifest_dir, Metadata};\nuse crate::opt::ConnectOpts;\nuse crate::Config;\nuse anyhow::{bail, Context};\nuse console::style;\nuse sqlx::Connection;\n\npub struct PrepareCtx<'a> {\n    pub config: &'a Config,\n    pub workspace: bool,\n    pub all: bool,\n    pub cargo: OsString,\n    pub cargo_args: Vec<String>,\n    pub metadata: Metadata,\n    pub connect_opts: ConnectOpts,\n}\n\nimpl PrepareCtx<'_> {\n    /// Path to the directory where cached queries should be placed.\n    fn prepare_dir(&self) -> anyhow::Result<PathBuf> {\n        if self.workspace {\n            Ok(self.metadata.workspace_root().join(\".sqlx\"))\n        } else {\n            Ok(manifest_dir(&self.cargo)?.join(\".sqlx\"))\n        }\n    }\n}\n\npub async fn run(\n    config: &Config,\n    check: bool,\n    all: bool,\n    workspace: bool,\n    connect_opts: ConnectOpts,\n    cargo_args: Vec<String>,\n) -> anyhow::Result<()> {\n    let cargo = env::var_os(\"CARGO\")\n        .context(\"failed to get value of `CARGO`; `prepare` subcommand may only be invoked as `cargo sqlx prepare`\")?;\n\n    anyhow::ensure!(\n        Path::new(\"Cargo.toml\").exists(),\n        r#\"Failed to read `Cargo.toml`.\nhint: This command only works in the manifest directory of a Cargo package or workspace.\"#\n    );\n\n    let metadata: Metadata = Metadata::from_current_directory(&cargo)?;\n    let ctx = PrepareCtx {\n        config,\n        workspace,\n        all,\n        cargo,\n        cargo_args,\n        metadata,\n        connect_opts,\n    };\n\n    if check {\n        prepare_check(&ctx).await\n    } else {\n        prepare(&ctx).await\n    }\n}\n\nasync fn prepare(ctx: &PrepareCtx<'_>) -> anyhow::Result<()> {\n    if ctx.connect_opts.database_url.is_some() {\n        check_backend(ctx.config, &ctx.connect_opts).await?;\n    }\n\n    let prepare_dir = ctx.prepare_dir()?;\n    run_prepare_step(ctx, &prepare_dir)?;\n\n    // Warn if no queries were generated. Glob since the directory may contain unrelated files.\n    if glob_query_files(prepare_dir)?.is_empty() {\n        println!(\"{} no queries found\", style(\"warning:\").yellow());\n        return Ok(());\n    }\n\n    if ctx.workspace {\n        println!(\n            \"query data written to .sqlx in the workspace root; \\\n             please check this into version control\"\n        );\n    } else {\n        println!(\n            \"query data written to .sqlx in the current directory; \\\n             please check this into version control\"\n        );\n    }\n    Ok(())\n}\n\nasync fn prepare_check(ctx: &PrepareCtx<'_>) -> anyhow::Result<()> {\n    if ctx.connect_opts.database_url.is_some() {\n        check_backend(ctx.config, &ctx.connect_opts).await?;\n    }\n\n    // Re-generate and store the queries in a separate directory from both the prepared\n    // queries and the ones generated by `cargo check`, to avoid conflicts.\n    let prepare_dir = ctx.prepare_dir()?;\n    let cache_dir = ctx.metadata.target_directory().join(\"sqlx-prepare-check\");\n    run_prepare_step(ctx, &cache_dir)?;\n\n    // Compare .sqlx to cache.\n    let prepare_filenames: HashSet<String> = glob_query_files(&prepare_dir)?\n        .into_iter()\n        .filter_map(|path| path.file_name().map(|f| f.to_string_lossy().into_owned()))\n        .collect();\n    let cache_filenames: HashSet<String> = glob_query_files(&cache_dir)?\n        .into_iter()\n        .filter_map(|path| path.file_name().map(|f| f.to_string_lossy().into_owned()))\n        .collect();\n\n    // Error: files in cache but not .sqlx.\n    if cache_filenames\n        .difference(&prepare_filenames)\n        .next()\n        .is_some()\n    {\n        bail!(\"prepare check failed: .sqlx is missing one or more queries; you should re-run sqlx prepare\");\n    }\n    // Warn: files in .sqlx but not cache.\n    if prepare_filenames\n        .difference(&cache_filenames)\n        .next()\n        .is_some()\n    {\n        println!(\n            \"{} potentially unused queries found in .sqlx; you may want to re-run sqlx prepare\",\n            style(\"warning:\").yellow()\n        );\n    }\n\n    // Compare file contents as JSON to ignore superficial differences.\n    // Everything in cache checked to be in .sqlx already.\n    for filename in cache_filenames {\n        let prepare_json = load_json_file(prepare_dir.join(&filename))?;\n        let cache_json = load_json_file(cache_dir.join(&filename))?;\n        if prepare_json != cache_json {\n            bail!(\"prepare check failed: one or more query files differ ({}); you should re-run sqlx prepare\", filename);\n        }\n    }\n\n    Ok(())\n}\n\nfn run_prepare_step(ctx: &PrepareCtx, cache_dir: &Path) -> anyhow::Result<()> {\n    // Create and/or clean the directory.\n    fs::create_dir_all(cache_dir).context(format!(\n        \"Failed to create query cache directory: {:?}\",\n        cache_dir\n    ))?;\n\n    // Create directory to hold temporary query files before they get persisted to SQLX_OFFLINE_DIR\n    let tmp_dir = ctx.metadata.target_directory().join(\"sqlx-tmp\");\n    fs::create_dir_all(&tmp_dir).context(format!(\n        \"Failed to create temporary query cache directory: {:?}\",\n        cache_dir\n    ))?;\n\n    // Only delete sqlx-*.json files to avoid accidentally deleting any user data.\n    for query_file in glob_query_files(cache_dir).context(\"Failed to read query cache files\")? {\n        fs::remove_file(&query_file)\n            .with_context(|| format!(\"Failed to delete query file: {}\", query_file.display()))?;\n    }\n\n    // Try only triggering a recompile on crates that use `sqlx-macros` falling back to a full\n    // clean on error\n    setup_minimal_project_recompile(&ctx.cargo, &ctx.metadata, ctx.all, ctx.workspace)?;\n\n    // Compile the queries.\n    let check_status = {\n        let mut check_command = Command::new(&ctx.cargo);\n        check_command\n            .arg(\"check\")\n            .args(&ctx.cargo_args)\n            .env(\"SQLX_TMP\", tmp_dir)\n            .env(\"SQLX_OFFLINE\", \"false\")\n            .env(\"SQLX_OFFLINE_DIR\", cache_dir);\n\n        if let Some(database_url) = &ctx.connect_opts.database_url {\n            check_command.env(\"DATABASE_URL\", database_url);\n        }\n\n        // `cargo check` recompiles on changed rust flags which can be set either via the env var\n        // or through the `rustflags` field in `$CARGO_HOME/config` when the env var isn't set.\n        // Because of this we only pass in `$RUSTFLAGS` when present.\n        if let Ok(rustflags) = env::var(\"RUSTFLAGS\") {\n            check_command.env(\"RUSTFLAGS\", rustflags);\n        }\n\n        check_command.status()?\n    };\n    if !check_status.success() {\n        bail!(\"`cargo check` failed with status: {}\", check_status);\n    }\n\n    Ok(())\n}\n\n#[derive(Debug, PartialEq)]\nstruct ProjectRecompileAction {\n    // The names of the packages\n    clean_packages: Vec<String>,\n    touch_paths: Vec<PathBuf>,\n}\n\n/// Sets up recompiling only crates that depend on `sqlx-macros`\n///\n/// This gets a listing of all crates that depend on `sqlx-macros` (direct and transitive). The\n/// crates within the current workspace have their source file's mtimes updated while crates\n/// outside the workspace are selectively `cargo clean -p`ed. In this way we can trigger a\n/// recompile of crates that may be using compile-time macros without forcing a full recompile.\n///\n/// If `workspace` is false, only the current package will have its files' mtimes updated.\nfn setup_minimal_project_recompile(\n    cargo: impl AsRef<OsStr>,\n    metadata: &Metadata,\n    all: bool,\n    workspace: bool,\n) -> anyhow::Result<()> {\n    let recompile_action: ProjectRecompileAction = if workspace {\n        minimal_project_recompile_action(metadata, all)\n    } else {\n        // Only touch the current crate.\n        ProjectRecompileAction {\n            clean_packages: Vec::new(),\n            touch_paths: metadata.current_package()\n                .context(\"failed to get package in current working directory, pass `--workspace` if running from a workspace root\")?\n                .src_paths()\n                .to_vec(),\n        }\n    };\n\n    if let Err(err) = minimal_project_clean(&cargo, recompile_action) {\n        println!(\n            \"Failed minimal recompile setup. Cleaning entire project. Err: {}\",\n            err\n        );\n        let clean_status = Command::new(&cargo).arg(\"clean\").status()?;\n        if !clean_status.success() {\n            bail!(\"`cargo clean` failed with status: {}\", clean_status);\n        }\n    }\n\n    Ok(())\n}\n\nfn minimal_project_clean(\n    cargo: impl AsRef<OsStr>,\n    action: ProjectRecompileAction,\n) -> anyhow::Result<()> {\n    let ProjectRecompileAction {\n        clean_packages,\n        touch_paths,\n    } = action;\n\n    // Update the modified timestamp of package files to force a selective recompilation.\n    for file in touch_paths {\n        let now = filetime::FileTime::now();\n        filetime::set_file_times(&file, now, now)\n            .with_context(|| format!(\"Failed to update mtime for {file:?}\"))?;\n    }\n\n    // Clean entire packages.\n    for pkg_id in &clean_packages {\n        let clean_status = Command::new(&cargo)\n            .args([\"clean\", \"-p\", pkg_id])\n            .status()?;\n\n        if !clean_status.success() {\n            bail!(\"`cargo clean -p {}` failed\", pkg_id);\n        }\n    }\n\n    Ok(())\n}\n\nfn minimal_project_recompile_action(metadata: &Metadata, all: bool) -> ProjectRecompileAction {\n    // Get all the packages that depend on `sqlx-macros`\n    let mut sqlx_macros_dependents = BTreeSet::new();\n    let sqlx_macros_ids: BTreeSet<_> = metadata\n        .entries()\n        // We match just by name instead of name and url because some people may have it installed\n        // through different means like vendoring\n        .filter(|(_, package)| package.name() == \"sqlx-macros\")\n        .map(|(id, _)| id)\n        .collect();\n    for sqlx_macros_id in sqlx_macros_ids {\n        sqlx_macros_dependents.extend(metadata.all_dependents_of(sqlx_macros_id));\n    }\n\n    // Figure out which `sqlx-macros` dependents are in the workspace vs out\n    let mut in_workspace_dependents = Vec::new();\n    let mut out_of_workspace_dependents = Vec::new();\n    for dependent in sqlx_macros_dependents {\n        if metadata.workspace_members().contains(dependent) {\n            in_workspace_dependents.push(dependent);\n        } else {\n            out_of_workspace_dependents.push(dependent);\n        }\n    }\n\n    // In-workspace dependents have their source file's mtime updated.\n    let files_to_touch: Vec<_> = in_workspace_dependents\n        .iter()\n        .filter_map(|id| {\n            metadata\n                .package(id)\n                .map(|package| package.src_paths().to_owned())\n        })\n        .flatten()\n        .collect();\n\n    // Out-of-workspace get `cargo clean -p <PKGID>`ed, only if --all is set.\n    let packages_to_clean: Vec<_> = if all {\n        out_of_workspace_dependents\n            .iter()\n            .filter_map(|id| {\n                metadata\n                    .package(id)\n                    .map(|package| package.name().to_owned())\n            })\n            // Do not clean sqlx, it depends on sqlx-macros but has no queries to prepare itself.\n            .filter(|name| name != \"sqlx\")\n            .collect()\n    } else {\n        Vec::new()\n    };\n\n    ProjectRecompileAction {\n        clean_packages: packages_to_clean,\n        touch_paths: files_to_touch,\n    }\n}\n\n/// Find all `query-*.json` files in a directory.\nfn glob_query_files(path: impl AsRef<Path>) -> anyhow::Result<Vec<PathBuf>> {\n    let path = path.as_ref();\n    let pattern = path.join(\"query-*.json\");\n    glob::glob(\n        pattern\n            .to_str()\n            .context(\"query cache path is invalid UTF-8\")?,\n    )\n    .with_context(|| format!(\"failed to read query cache path: {}\", path.display()))?\n    .collect::<Result<Vec<_>, _>>()\n    .context(\"glob failed\")\n}\n\n/// Load the JSON contents of a query data file.\nfn load_json_file(path: impl AsRef<Path>) -> anyhow::Result<serde_json::Value> {\n    let path = path.as_ref();\n    let file_bytes =\n        fs::read(path).with_context(|| format!(\"failed to load file: {}\", path.display()))?;\n    Ok(serde_json::from_slice(&file_bytes)?)\n}\n\nasync fn check_backend(config: &Config, opts: &ConnectOpts) -> anyhow::Result<()> {\n    crate::connect(config, opts).await?.close().await?;\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use std::assert_eq;\n\n    #[test]\n    fn minimal_project_recompile_action_works() -> anyhow::Result<()> {\n        let sample_metadata_path = Path::new(\"tests\")\n            .join(\"assets\")\n            .join(\"sample_metadata.json\");\n        let sample_metadata = std::fs::read_to_string(sample_metadata_path)?;\n        let metadata: Metadata = sample_metadata.parse()?;\n\n        let action = minimal_project_recompile_action(&metadata, false);\n        assert_eq!(\n            action,\n            ProjectRecompileAction {\n                clean_packages: vec![],\n                touch_paths: vec![\n                    \"/home/user/problematic/workspace/b_in_workspace_lib/src/lib.rs\".into(),\n                    \"/home/user/problematic/workspace/c_in_workspace_bin/src/main.rs\".into(),\n                ],\n            }\n        );\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-cli/tests/add.rs",
    "content": "use anyhow::Context;\nuse assert_cmd::cargo_bin_cmd;\nuse std::cmp::Ordering;\nuse std::fs::read_dir;\nuse std::ops::Index;\nuse std::path::{Path, PathBuf};\nuse tempfile::TempDir;\n\n#[derive(Debug, PartialEq, Eq)]\nstruct FileName {\n    id: u64,\n    description: String,\n    suffix: String,\n}\n\nimpl PartialOrd<Self> for FileName {\n    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {\n        if self.id != other.id {\n            self.id.partial_cmp(&other.id)\n        } else {\n            self.suffix.partial_cmp(&other.suffix)\n        }\n    }\n}\n\nimpl FileName {\n    fn assert_is_timestamp(&self) {\n        assert!(\n            self.id > 20200101000000,\n            \"{self:?} is too low for a timestamp\"\n        );\n    }\n}\n\nimpl From<PathBuf> for FileName {\n    fn from(path: PathBuf) -> Self {\n        let filename = path.file_name().unwrap().to_string_lossy();\n        let (id, rest) = filename.split_once(\"_\").unwrap();\n        let id: u64 = id.parse().unwrap();\n        let (description, suffix) = rest.split_once(\".\").unwrap();\n        Self {\n            id,\n            description: description.to_string(),\n            suffix: suffix.to_string(),\n        }\n    }\n}\n\nstruct AddMigrationsResult(Vec<FileName>);\nimpl AddMigrationsResult {\n    fn len(&self) -> usize {\n        self.0.len()\n    }\n    fn assert_is_reversible(&self) {\n        let mut up_cnt = 0;\n        let mut down_cnt = 0;\n        for file in self.0.iter() {\n            if file.suffix == \"down.sql\" {\n                down_cnt += 1;\n            } else if file.suffix == \"up.sql\" {\n                up_cnt += 1;\n            } else {\n                panic!(\"unknown suffix for {file:?}\");\n            }\n            assert!(file.description.starts_with(\"hello_world\"));\n        }\n        assert_eq!(up_cnt, down_cnt);\n    }\n    fn assert_is_not_reversible(&self) {\n        for file in self.0.iter() {\n            assert_eq!(file.suffix, \"sql\");\n            assert!(file.description.starts_with(\"hello_world\"));\n        }\n    }\n}\n\nimpl Index<usize> for AddMigrationsResult {\n    type Output = FileName;\n\n    fn index(&self, index: usize) -> &Self::Output {\n        &self.0[index]\n    }\n}\n\nstruct AddMigrations {\n    tempdir: TempDir,\n    config_arg: Option<String>,\n}\n\nimpl AddMigrations {\n    fn new() -> anyhow::Result<Self> {\n        anyhow::Ok(Self {\n            tempdir: TempDir::new()?,\n            config_arg: None,\n        })\n    }\n\n    fn with_config(mut self, filename: &str) -> anyhow::Result<Self> {\n        let path = format!(\"./tests/assets/{filename}\");\n\n        let path = std::fs::canonicalize(&path)\n            .with_context(|| format!(\"error canonicalizing path {path:?}\"))?;\n\n        let path = path\n            .to_str()\n            .with_context(|| format!(\"canonicalized version of path {path:?} is not UTF-8\"))?;\n\n        self.config_arg = Some(format!(\"--config={path}\"));\n        Ok(self)\n    }\n\n    fn run(\n        &self,\n        description: &str,\n        revesible: bool,\n        timestamp: bool,\n        sequential: bool,\n        expect_success: bool,\n    ) -> anyhow::Result<&'_ Self> {\n        let cmd_result = cargo_bin_cmd!(\"cargo-sqlx\")\n            .current_dir(&self.tempdir)\n            .args(\n                [\n                    vec![\"sqlx\", \"migrate\", \"add\", description],\n                    self.config_arg.as_deref().map_or(vec![], |arg| vec![arg]),\n                    match revesible {\n                        true => vec![\"-r\"],\n                        false => vec![],\n                    },\n                    match timestamp {\n                        true => vec![\"--timestamp\"],\n                        false => vec![],\n                    },\n                    match sequential {\n                        true => vec![\"--sequential\"],\n                        false => vec![],\n                    },\n                ]\n                .concat(),\n            )\n            .env(\"RUST_BACKTRACE\", \"1\")\n            .assert();\n        if expect_success {\n            cmd_result.success();\n        } else {\n            cmd_result.failure();\n        }\n        anyhow::Ok(self)\n    }\n    fn fs_output(&self) -> anyhow::Result<AddMigrationsResult> {\n        let files = recurse_files(&self.tempdir)?;\n        let mut fs_paths = Vec::with_capacity(files.len());\n        for path in files {\n            let relative_path = path.strip_prefix(self.tempdir.path())?.to_path_buf();\n            fs_paths.push(FileName::from(relative_path));\n        }\n        Ok(AddMigrationsResult(fs_paths))\n    }\n}\n\nfn recurse_files(path: impl AsRef<Path>) -> anyhow::Result<Vec<PathBuf>> {\n    let mut buf = vec![];\n    let entries = read_dir(path)?;\n\n    for entry in entries {\n        let entry = entry?;\n        let meta = entry.metadata()?;\n\n        if meta.is_dir() {\n            let mut subdir = recurse_files(entry.path())?;\n            buf.append(&mut subdir);\n        }\n\n        if meta.is_file() {\n            buf.push(entry.path());\n        }\n    }\n    buf.sort();\n    Ok(buf)\n}\n\n#[test]\nfn add_migration_error_ambiguous() -> anyhow::Result<()> {\n    for reversible in [true, false] {\n        let files = AddMigrations::new()?\n            // Passing both `--timestamp` and `--reversible` should result in an error.\n            .run(\"hello world\", reversible, true, true, false)?\n            .fs_output()?;\n\n        // Assert that no files are created\n        assert_eq!(files.0, []);\n    }\n    Ok(())\n}\n\n#[test]\nfn add_migration_sequential() -> anyhow::Result<()> {\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world\", false, false, true, true)?\n            .fs_output()?;\n        assert_eq!(files.len(), 1);\n        files.assert_is_not_reversible();\n        assert_eq!(files.0[0].id, 1);\n    }\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world1\", false, false, true, true)?\n            .run(\"hello world2\", true, false, true, true)?\n            .fs_output()?;\n        assert_eq!(files.len(), 3);\n        assert_eq!(files.0[0].id, 1);\n        assert_eq!(files.0[1].id, 2);\n        assert_eq!(files.0[1].suffix, \"down.sql\");\n        assert_eq!(files.0[2].id, 2);\n        assert_eq!(files.0[2].suffix, \"up.sql\");\n    }\n    Ok(())\n}\n#[test]\nfn add_migration_sequential_reversible() -> anyhow::Result<()> {\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world\", true, false, true, true)?\n            .fs_output()?;\n        assert_eq!(files.len(), 2);\n        files.assert_is_reversible();\n        assert_eq!(files.0[0].id, 1);\n        assert_eq!(files.0[0].id, 1);\n    }\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world1\", true, false, true, true)?\n            .run(\"hello world2\", true, true, false, true)?\n            .run(\"hello world3\", true, false, true, true)?\n            .fs_output()?;\n        assert_eq!(files.len(), 6);\n        files.assert_is_reversible();\n        assert_eq!(files.0[0].id, 1);\n        assert_eq!(files.0[1].id, 1);\n        // sequential -> timestamp is one way\n        files.0[2].assert_is_timestamp();\n        files.0[3].assert_is_timestamp();\n        files.0[4].assert_is_timestamp();\n        files.0[5].assert_is_timestamp();\n    }\n    Ok(())\n}\n\n#[test]\nfn add_migration_timestamp() -> anyhow::Result<()> {\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world\", false, true, false, true)?\n            .fs_output()?;\n        assert_eq!(files.len(), 1);\n        files.assert_is_not_reversible();\n        files.0[0].assert_is_timestamp();\n    }\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world1\", false, true, false, true)?\n            .run(\"hello world2\", true, false, true, true)?\n            .fs_output()?;\n        assert_eq!(files.len(), 3);\n        files.0[0].assert_is_timestamp();\n        // sequential -> timestamp is one way\n        files.0[1].assert_is_timestamp();\n        files.0[2].assert_is_timestamp();\n    }\n    Ok(())\n}\n\n#[test]\nfn add_migration_timestamp_reversible() -> anyhow::Result<()> {\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world\", true, false, false, true)?\n            .fs_output()?;\n\n        assert_eq!(files.len(), 2);\n        files.assert_is_reversible();\n\n        // .up.sql and .down.sql\n        files[0].assert_is_timestamp();\n        assert_eq!(files[1].id, files[0].id);\n    }\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world\", true, true, false, true)?\n            .fs_output()?;\n\n        assert_eq!(files.len(), 2);\n        files.assert_is_reversible();\n\n        // .up.sql and .down.sql\n        files[0].assert_is_timestamp();\n        assert_eq!(files[1].id, files[0].id);\n    }\n    {\n        let files = AddMigrations::new()?\n            .run(\"hello world1\", true, true, false, true)?\n            // Reversible should be inferred, but sequential should be forced\n            .run(\"hello world2\", false, false, true, true)?\n            .fs_output()?;\n\n        assert_eq!(files.len(), 4);\n        files.assert_is_reversible();\n\n        // First pair: .up.sql and .down.sql\n        files[0].assert_is_timestamp();\n        assert_eq!(files[1].id, files[0].id);\n\n        // Second pair; we set `--sequential` so this version should be one higher\n        assert_eq!(files[2].id, files[1].id + 1);\n        assert_eq!(files[3].id, files[1].id + 1);\n    }\n    Ok(())\n}\n\n#[test]\nfn add_migration_config_default_type_reversible() -> anyhow::Result<()> {\n    let files = AddMigrations::new()?\n        .with_config(\"config_default_type_reversible.toml\")?\n        // Type should default to reversible without any flags\n        .run(\"hello world\", false, false, false, true)?\n        .run(\"hello world2\", false, false, false, true)?\n        .run(\"hello world3\", false, false, false, true)?\n        .fs_output()?;\n\n    assert_eq!(files.len(), 6);\n    files.assert_is_reversible();\n\n    files[0].assert_is_timestamp();\n    assert_eq!(files[1].id, files[0].id);\n\n    files[2].assert_is_timestamp();\n    assert_eq!(files[3].id, files[2].id);\n\n    files[4].assert_is_timestamp();\n    assert_eq!(files[5].id, files[4].id);\n\n    Ok(())\n}\n\n#[test]\nfn add_migration_config_default_versioning_sequential() -> anyhow::Result<()> {\n    let files = AddMigrations::new()?\n        .with_config(\"config_default_versioning_sequential.toml\")?\n        // Versioning should default to timestamp without any flags\n        .run(\"hello world\", false, false, false, true)?\n        .run(\"hello world2\", false, false, false, true)?\n        .run(\"hello world3\", false, false, false, true)?\n        .fs_output()?;\n\n    assert_eq!(files.len(), 3);\n    files.assert_is_not_reversible();\n\n    assert_eq!(files[0].id, 1);\n    assert_eq!(files[1].id, 2);\n    assert_eq!(files[2].id, 3);\n\n    Ok(())\n}\n\n#[test]\nfn add_migration_config_default_versioning_timestamp() -> anyhow::Result<()> {\n    let migrations = AddMigrations::new()?;\n\n    migrations\n        .run(\"hello world\", false, false, true, true)?\n        // Default config should infer sequential even without passing `--sequential`\n        .run(\"hello world2\", false, false, false, true)?\n        .run(\"hello world3\", false, false, false, true)?;\n\n    let files = migrations.fs_output()?;\n\n    assert_eq!(files.len(), 3);\n    files.assert_is_not_reversible();\n\n    assert_eq!(files[0].id, 1);\n    assert_eq!(files[1].id, 2);\n    assert_eq!(files[2].id, 3);\n\n    // Now set a config that uses `default-versioning = \"timestamp\"`\n    let migrations = migrations.with_config(\"config_default_versioning_timestamp.toml\")?;\n\n    // Now the default should be a timestamp\n    migrations\n        .run(\"hello world4\", false, false, false, true)?\n        .run(\"hello world5\", false, false, false, true)?;\n\n    let files = migrations.fs_output()?;\n\n    assert_eq!(files.len(), 5);\n    files.assert_is_not_reversible();\n\n    assert_eq!(files[0].id, 1);\n    assert_eq!(files[1].id, 2);\n    assert_eq!(files[2].id, 3);\n\n    files[3].assert_is_timestamp();\n    files[4].assert_is_timestamp();\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-cli/tests/assets/config_default_type_reversible.toml",
    "content": "[migrate.defaults]\nmigration-type = \"reversible\""
  },
  {
    "path": "sqlx-cli/tests/assets/config_default_versioning_sequential.toml",
    "content": "[migrate.defaults]\nmigration-versioning = \"sequential\""
  },
  {
    "path": "sqlx-cli/tests/assets/config_default_versioning_timestamp.toml",
    "content": "[migrate.defaults]\nmigration-versioning = \"timestamp\""
  },
  {
    "path": "sqlx-cli/tests/assets/sample_metadata.json",
    "content": "{\n  \"packages\": [\n    {\n      \"name\": \"ahash\",\n      \"version\": \"0.7.6\",\n      \"id\": \"ahash 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A non-cryptographic hash function using AES-NI for high performance\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"fnv\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.5\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"fxhash\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"no-panic\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.10\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"seahash\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^4.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.59\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"version_check\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"const-random\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.12\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"windows\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonfly\\\", target_os = \\\"solaris\\\", target_os = \\\"illumos\\\", target_os = \\\"fuchsia\\\", target_os = \\\"redox\\\", target_os = \\\"cloudabi\\\", target_os = \\\"haiku\\\", target_os = \\\"vxworks\\\", target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"getrandom\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"windows\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonfly\\\", target_os = \\\"solaris\\\", target_os = \\\"illumos\\\", target_os = \\\"fuchsia\\\", target_os = \\\"redox\\\", target_os = \\\"cloudabi\\\", target_os = \\\"haiku\\\", target_os = \\\"vxworks\\\", target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.117\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"windows\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonfly\\\", target_os = \\\"solaris\\\", target_os = \\\"illumos\\\", target_os = \\\"fuchsia\\\", target_os = \\\"redox\\\", target_os = \\\"cloudabi\\\", target_os = \\\"haiku\\\", target_os = \\\"vxworks\\\", target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"alloc\"\n          ],\n          \"target\": \"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"const-random\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.12\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(not(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"windows\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonfly\\\", target_os = \\\"solaris\\\", target_os = \\\"illumos\\\", target_os = \\\"fuchsia\\\", target_os = \\\"redox\\\", target_os = \\\"cloudabi\\\", target_os = \\\"haiku\\\", target_os = \\\"vxworks\\\", target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\")))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.117\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(not(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"windows\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonfly\\\", target_os = \\\"solaris\\\", target_os = \\\"illumos\\\", target_os = \\\"fuchsia\\\", target_os = \\\"redox\\\", target_os = \\\"cloudabi\\\", target_os = \\\"haiku\\\", target_os = \\\"vxworks\\\", target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\")))\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"ahash\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"map_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/tests/map_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"nopanic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/tests/nopanic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/tests/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ahash\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/tests/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"map\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/tests/map_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/./build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"compile-time-rng\": [\n          \"const-random\"\n        ],\n        \"const-random\": [\n          \"dep:const-random\"\n        ],\n        \"default\": [\n          \"std\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ahash-0.7.6/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"std\"\n            ],\n            \"rustc-args\": [\n              \"-C\",\n              \"target-feature=+aes\"\n            ],\n            \"rustdoc-args\": [\n              \"-C\",\n              \"target-feature=+aes\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Tom Kaitchuck <Tom.Kaitchuck@gmail.com>\"\n      ],\n      \"categories\": [\n        \"algorithms\",\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"hash\",\n        \"hasher\",\n        \"hashmap\",\n        \"aes\",\n        \"no-std\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/tkaitchuck/ahash\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/ahash\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"atoi\",\n      \"version\": \"0.4.0\",\n      \"id\": \"atoi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Parse integers directly from `[u8]` slices in safe code\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"num-traits\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.12\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"atoi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/atoi-0.4.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"benches\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/atoi-0.4.0/benches/benches.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/atoi-0.4.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Markus Klein <markus-klein@live.de>\"\n      ],\n      \"categories\": [\n        \"parsing\"\n      ],\n      \"keywords\": [\n        \"atoi\",\n        \"conversion\",\n        \"integer\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/pacman82/atoi-rs\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/atoi/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"autocfg\",\n      \"version\": \"1.1.0\",\n      \"id\": \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"Automatic cfg for Rust compiler features\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"autocfg\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"versions\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/examples/versions.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"traits\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/examples/traits.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"integers\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/examples/integers.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"paths\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/examples/paths.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rustflags\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/tests/rustflags.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/autocfg-1.1.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Josh Stone <cuviper@gmail.com>\"\n      ],\n      \"categories\": [\n        \"development-tools::build-utils\"\n      ],\n      \"keywords\": [\n        \"rustc\",\n        \"build\",\n        \"autoconf\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/cuviper/autocfg\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"b_in_workspace_lib\",\n      \"version\": \"0.1.0\",\n      \"id\": \"b_in_workspace_lib 0.1.0 (path+file:///home/user/problematic/workspace/b_in_workspace_lib)\",\n      \"license\": null,\n      \"license_file\": null,\n      \"description\": null,\n      \"source\": null,\n      \"dependencies\": [\n        {\n          \"name\": \"sqlx\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"offline\",\n            \"runtime-tokio-rustls\",\n            \"sqlite\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"b_in_workspace_lib\",\n          \"src_path\": \"/home/user/problematic/workspace/b_in_workspace_lib/src/lib.rs\",\n          \"edition\": \"2021\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/problematic/workspace/b_in_workspace_lib/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": null,\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2021\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"base64\",\n      \"version\": \"0.13.0\",\n      \"id\": \"base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"encodes and decodes base64 as bytes or utf8\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.3.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"structopt\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"base64\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"make_tables\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/examples/make_tables.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"base64\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/examples/base64.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"encode\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/tests/encode.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"helpers\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/tests/helpers.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/tests/tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"decode\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/tests/decode.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"benchmarks\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/benches/benchmarks.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/base64-0.13.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Alice Maz <alice@alicemaz.com>\",\n        \"Marshall Pierce <marshall@mpierce.org>\"\n      ],\n      \"categories\": [\n        \"encoding\"\n      ],\n      \"keywords\": [\n        \"base64\",\n        \"utf8\",\n        \"encode\",\n        \"decode\",\n        \"no_std\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/marshallpierce/rust-base64\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/base64\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"bitflags\",\n      \"version\": \"1.3.2\",\n      \"id\": \"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A macro to generate structures which behave like bitflags.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_derive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"walkdir\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"bitflags\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.3.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"basic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.3.2/tests/basic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compile\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.3.2/tests/compile.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"default\": [],\n        \"example_generated\": [],\n        \"rustc-dep-of-std\": [\n          \"core\",\n          \"compiler_builtins\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bitflags-1.3.2/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"example_generated\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The Rust Project Developers\"\n      ],\n      \"categories\": [\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"bit\",\n        \"bitmask\",\n        \"bitflags\",\n        \"flags\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/bitflags/bitflags\",\n      \"homepage\": \"https://github.com/bitflags/bitflags\",\n      \"documentation\": \"https://docs.rs/bitflags\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"block-buffer\",\n      \"version\": \"0.9.0\",\n      \"id\": \"block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Fixed size buffer for block processing of data\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"block-padding\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"generic-array\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.14\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"block-buffer\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/block-buffer-0.9.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"block-padding\": [\n          \"dep:block-padding\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/block-buffer-0.9.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"RustCrypto Developers\"\n      ],\n      \"categories\": [\n        \"cryptography\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"block\",\n        \"buffer\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/RustCrypto/utils\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/block-buffer\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"bumpalo\",\n      \"version\": \"3.9.1\",\n      \"id\": \"bumpalo 3.9.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A fast bump allocation arena for Rust.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quickcheck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"bumpalo\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bumpalo-3.9.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"try_alloc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bumpalo-3.9.1/tests/try_alloc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"benches\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bumpalo-3.9.1/benches/benches.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"collections\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"allocator_api\": [],\n        \"boxed\": [],\n        \"collections\": [],\n        \"default\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bumpalo-3.9.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Nick Fitzgerald <fitzgen@gmail.com>\"\n      ],\n      \"categories\": [\n        \"memory-management\",\n        \"rust-patterns\",\n        \"no-std\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"./README.md\",\n      \"repository\": \"https://github.com/fitzgen/bumpalo\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/bumpalo\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"byteorder\",\n      \"version\": \"1.4.3\",\n      \"id\": \"byteorder 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Unlicense OR MIT\",\n      \"license_file\": null,\n      \"description\": \"Library for reading/writing numbers in big-endian and little-endian.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"quickcheck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"byteorder\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-1.4.3/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-1.4.3/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"i128\": [],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/byteorder-1.4.3/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Andrew Gallant <jamslam@gmail.com>\"\n      ],\n      \"categories\": [\n        \"encoding\",\n        \"parsing\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"byte\",\n        \"endian\",\n        \"big-endian\",\n        \"little-endian\",\n        \"binary\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/BurntSushi/byteorder\",\n      \"homepage\": \"https://github.com/BurntSushi/byteorder\",\n      \"documentation\": \"https://docs.rs/byteorder\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"bytes\",\n      \"version\": \"1.1.0\",\n      \"id\": \"bytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Types and traits for working with bytes\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.60\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"alloc\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"loom\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(loom)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"bytes\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_iter.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_buf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_buf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_bytes_vec_alloc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_bytes_vec_alloc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_debug\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_debug.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_buf_mut\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_buf_mut.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_serde\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_serde.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_bytes\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_bytes.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_take\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_take.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_chain\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_chain.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_reader\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_reader.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_bytes_odd_alloc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/tests/test_bytes_odd_alloc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bytes_mut\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/benches/bytes_mut.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"buf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/benches/buf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bytes\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/benches/bytes.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/bytes-1.1.0/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Carl Lerche <me@carllerche.com>\",\n        \"Sean McArthur <sean@seanmonstar.com>\"\n      ],\n      \"categories\": [\n        \"network-programming\",\n        \"data-structures\"\n      ],\n      \"keywords\": [\n        \"buffers\",\n        \"zero-copy\",\n        \"io\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/tokio-rs/bytes\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"c_in_workspace_bin\",\n      \"version\": \"0.1.0\",\n      \"id\": \"c_in_workspace_bin 0.1.0 (path+file:///home/user/problematic/workspace/c_in_workspace_bin)\",\n      \"license\": null,\n      \"license_file\": null,\n      \"description\": null,\n      \"source\": null,\n      \"dependencies\": [\n        {\n          \"name\": \"b_in_workspace_lib\",\n          \"source\": null,\n          \"req\": \"*\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null,\n          \"path\": \"/home/user/problematic/workspace/b_in_workspace_lib\"\n        },\n        {\n          \"name\": \"sqlx\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"offline\",\n            \"runtime-tokio-rustls\",\n            \"sqlite\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"bin\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"c_in_workspace_bin\",\n          \"src_path\": \"/home/user/problematic/workspace/c_in_workspace_bin/src/main.rs\",\n          \"edition\": \"2021\",\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/problematic/workspace/c_in_workspace_bin/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": null,\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2021\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"cc\",\n      \"version\": \"1.0.73\",\n      \"id\": \"cc 1.0.73 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A build-time dependency for Cargo build scripts to assist in invoking the native\\nC compiler to compile native C code into a static archive to be linked into Rust\\ncode.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"jobserver\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.16\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tempfile\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"cc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bin\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"gcc-shim\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/src/bin/gcc-shim.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cxxflags\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/tests/cxxflags.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cc_env\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/tests/cc_env.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cflags\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/tests/cflags.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"jobserver\": [\n          \"dep:jobserver\"\n        ],\n        \"parallel\": [\n          \"jobserver\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cc-1.0.73/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Alex Crichton <alex@alexcrichton.com>\"\n      ],\n      \"categories\": [\n        \"development-tools::build-utils\"\n      ],\n      \"keywords\": [\n        \"build-dependencies\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/alexcrichton/cc-rs\",\n      \"homepage\": \"https://github.com/alexcrichton/cc-rs\",\n      \"documentation\": \"https://docs.rs/cc\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"cfg-if\",\n      \"version\": \"1.0.0\",\n      \"id\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A macro to ergonomically define an item depending on a large number of #[cfg]\\nparameters. Structured like an if-else chain, the first matching branch is the\\nitem that gets emitted.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"cfg-if\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-1.0.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"xcrate\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-1.0.0/tests/xcrate.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"rustc-dep-of-std\": [\n          \"core\",\n          \"compiler_builtins\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cfg-if-1.0.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Alex Crichton <alex@alexcrichton.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/alexcrichton/cfg-if\",\n      \"homepage\": \"https://github.com/alexcrichton/cfg-if\",\n      \"documentation\": \"https://docs.rs/cfg-if\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"cpufeatures\",\n      \"version\": \"0.2.2\",\n      \"id\": \"cpufeatures 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Lightweight runtime CPU feature detection for x86/x86_64 and aarch64 with\\nno_std support and support for mobile targets including Android and iOS\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.68\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"aarch64-apple-darwin\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.68\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"aarch64-linux-android\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.68\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"cpufeatures\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cpufeatures-0.2.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"x86\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cpufeatures-0.2.2/tests/x86.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"aarch64\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cpufeatures-0.2.2/tests/aarch64.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/cpufeatures-0.2.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"RustCrypto Developers\"\n      ],\n      \"categories\": [\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"cpuid\",\n        \"target-feature\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/RustCrypto/utils\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/cpufeatures\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"crc\",\n      \"version\": \"2.1.0\",\n      \"id\": \"crc 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Rust implementation of CRC(16, 32, 64) with support of various standards\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"crc-catalog\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"crc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crc-2.1.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"crc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crc-2.1.0/tests/crc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crc-2.1.0/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crc-2.1.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Rui Hu <code@mrhooray.com>\",\n        \"Akhil Velagapudi <4@4khil.com>\"\n      ],\n      \"categories\": [\n        \"algorithms\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"crc\",\n        \"crc16\",\n        \"crc32\",\n        \"crc64\",\n        \"hash\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/mrhooray/crc-rs.git\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/crc\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"crc-catalog\",\n      \"version\": \"1.1.1\",\n      \"id\": \"crc-catalog 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Catalog of CRC algorithms (generated from http://reveng.sourceforge.net/crc-catalogue) expressed as simple Rust structs.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"crc-catalog\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crc-catalog-1.1.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crc-catalog-1.1.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Akhil Velagapudi <akhilvelagapudi@gmail.com>\"\n      ],\n      \"categories\": [\n        \"no-std\",\n        \"network-programming\"\n      ],\n      \"keywords\": [\n        \"crc\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/akhilles/crc-catalog.git\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"crossbeam-queue\",\n      \"version\": \"0.3.5\",\n      \"id\": \"crossbeam-queue 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Concurrent queues\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crossbeam-utils\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"crossbeam-queue\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-queue-0.3.5/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"seg_queue\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-queue-0.3.5/tests/seg_queue.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"array_queue\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-queue-0.3.5/tests/array_queue.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-queue-0.3.5/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"nightly\": [\n          \"crossbeam-utils/nightly\"\n        ],\n        \"std\": [\n          \"alloc\",\n          \"crossbeam-utils/std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-queue-0.3.5/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [\n        \"concurrency\",\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"queue\",\n        \"mpmc\",\n        \"lock-free\",\n        \"producer\",\n        \"consumer\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/crossbeam-rs/crossbeam\",\n      \"homepage\": \"https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-queue\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"crossbeam-utils\",\n      \"version\": \"0.8.8\",\n      \"id\": \"crossbeam-utils 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Utilities for concurrent programming\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"loom\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(crossbeam_loom)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"crossbeam-utils\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"parker\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/tests/parker.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"thread\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/tests/thread.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sharded_lock\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/tests/sharded_lock.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cache_padded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/tests/cache_padded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"atomic_cell\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/tests/atomic_cell.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"wait_group\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/tests/wait_group.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"atomic_cell\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/benches/atomic_cell.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"lazy_static\": [\n          \"dep:lazy_static\"\n        ],\n        \"loom\": [\n          \"dep:loom\"\n        ],\n        \"nightly\": [],\n        \"std\": [\n          \"lazy_static\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/crossbeam-utils-0.8.8/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [\n        \"algorithms\",\n        \"concurrency\",\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"scoped\",\n        \"thread\",\n        \"atomic\",\n        \"cache\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/crossbeam-rs/crossbeam\",\n      \"homepage\": \"https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"digest\",\n      \"version\": \"0.9.0\",\n      \"id\": \"digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Traits for cryptographic hash functions\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"blobby\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"generic-array\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.14\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"digest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/digest-0.9.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"blobby\": [\n          \"dep:blobby\"\n        ],\n        \"dev\": [\n          \"blobby\"\n        ],\n        \"std\": [\n          \"alloc\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/digest-0.9.0/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"RustCrypto Developers\"\n      ],\n      \"categories\": [\n        \"cryptography\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"digest\",\n        \"crypto\",\n        \"hash\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/RustCrypto/traits\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/digest\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"dotenv\",\n      \"version\": \"0.15.0\",\n      \"id\": \"dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"A `dotenv` implementation for Rust\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"clap\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tempfile\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^3.0.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"dotenv\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bin\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"dotenv\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/src/bin/dotenv.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"cli\"\n          ],\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"simple\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/examples/simple.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-variable-substitution\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-variable-substitution.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-from-filename\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-from-filename.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-from-path-iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-from-path-iter.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-var\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-var.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-default-location\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-default-location.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-from-path\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-from-path.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-from-filename-iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-from-filename-iter.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-vars\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-vars.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-dotenv-iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-dotenv-iter.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test-child-dir\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/tests/test-child-dir.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"clap\": [\n          \"dep:clap\"\n        ],\n        \"cli\": [\n          \"clap\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/dotenv-0.15.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Noemi Lapresta <noemi.lapresta@gmail.com>\",\n        \"Craig Hills <chills@gmail.com>\",\n        \"Mike Piccolo <mfpiccolo@gmail.com>\",\n        \"Alice Maz <alice@alicemaz.com>\",\n        \"Sean Griffin <sean@seantheprogrammer.com>\",\n        \"Adam Sharp <adam@sharplet.me>\",\n        \"Arpad Borsos <arpad.borsos@googlemail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"environment\",\n        \"env\",\n        \"dotenv\",\n        \"settings\",\n        \"config\"\n      ],\n      \"readme\": \"../README.md\",\n      \"repository\": \"https://github.com/dotenv-rs/dotenv\",\n      \"homepage\": \"https://github.com/dotenv-rs/dotenv\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"either\",\n      \"version\": \"1.6.1\",\n      \"id\": \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"The enum `Either` with variants `Left` and `Right` is a general purpose sum type with two cases.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"either\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/either-1.6.1/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"use_std\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"use_std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/either-1.6.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"serde\"\n            ]\n          }\n        },\n        \"release\": {\n          \"no-dev-version\": true,\n          \"tag-name\": \"{{version}}\"\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"bluss\"\n      ],\n      \"categories\": [\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"data-structure\",\n        \"no_std\"\n      ],\n      \"readme\": \"README-crates.io.md\",\n      \"repository\": \"https://github.com/bluss/either\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/either/1/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"flume\",\n      \"version\": \"0.10.12\",\n      \"id\": \"flume 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/MIT\",\n      \"license_file\": null,\n      \"description\": \"A blazingly fast multi-producer channel\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-sink\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"nanorand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"getrandom\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pin-project\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"spin\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.2\",\n          \"kind\": null,\n          \"rename\": \"spin1\",\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"mutex\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-std\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.9.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"attributes\",\n            \"unstable\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crossbeam-channel\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crossbeam-utils\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.5\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.16.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"rt\",\n            \"macros\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"waker-fn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"flume\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"async\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/examples/async.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"select\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/examples/select.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"simple\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/examples/simple.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"perf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/examples/perf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"async\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/async.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"basic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/basic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"list\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/list.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/iter.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/stream.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mpsc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/mpsc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"method_sharing\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/method_sharing.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"same_channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/same_channel.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"array\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/array.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ready\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/ready.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"never\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/never.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"thread_locals\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/thread_locals.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"select\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/select.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"after\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/after.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"select_macro\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/select_macro.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tick\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/tick.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"zero\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/zero.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"golang\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/tests/golang.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"basic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/benches/basic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"async\": [\n          \"futures-sink\",\n          \"futures-core\",\n          \"pin-project\"\n        ],\n        \"default\": [\n          \"async\",\n          \"select\",\n          \"eventual-fairness\"\n        ],\n        \"eventual-fairness\": [\n          \"async\",\n          \"nanorand\"\n        ],\n        \"futures-core\": [\n          \"dep:futures-core\"\n        ],\n        \"futures-sink\": [\n          \"dep:futures-sink\"\n        ],\n        \"nanorand\": [\n          \"dep:nanorand\"\n        ],\n        \"pin-project\": [\n          \"dep:pin-project\"\n        ],\n        \"select\": [],\n        \"spin\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/flume-0.10.12/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Joshua Barretto <joshua.s.barretto@gmail.com>\"\n      ],\n      \"categories\": [\n        \"concurrency\",\n        \"data-structures\"\n      ],\n      \"keywords\": [\n        \"mpsc\",\n        \"fifo\",\n        \"channel\",\n        \"thread\",\n        \"mpmc\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/zesterer/flume\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"form_urlencoded\",\n      \"version\": \"1.0.1\",\n      \"id\": \"form_urlencoded 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Parser and serializer for the application/x-www-form-urlencoded syntax, as used by HTML forms.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"matches\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"percent-encoding\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"form_urlencoded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/form_urlencoded-1.0.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/form_urlencoded-1.0.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The rust-url developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/servo/rust-url\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"futures-channel\",\n      \"version\": \"0.3.21\",\n      \"id\": \"futures-channel 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Channels for asynchronous communication using futures-rs.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-sink\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures-channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/tests/channel.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mpsc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/tests/mpsc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"oneshot\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/tests/oneshot.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mpsc-close\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/tests/mpsc-close.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_mpsc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/benches/sync_mpsc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [\n          \"futures-core/alloc\"\n        ],\n        \"cfg-target-has-atomic\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"futures-sink\": [\n          \"dep:futures-sink\"\n        ],\n        \"sink\": [\n          \"futures-sink\"\n        ],\n        \"std\": [\n          \"alloc\",\n          \"futures-core/std\"\n        ],\n        \"unstable\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-channel-0.3.21/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/futures-rs\",\n      \"homepage\": \"https://rust-lang.github.io/futures-rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.45\"\n    },\n    {\n      \"name\": \"futures-core\",\n      \"version\": \"0.3.21\",\n      \"id\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"The core traits and types in for the `futures` library.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures-core\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.21/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.21/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"cfg-target-has-atomic\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"std\": [\n          \"alloc\"\n        ],\n        \"unstable\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-core-0.3.21/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/futures-rs\",\n      \"homepage\": \"https://rust-lang.github.io/futures-rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"futures-executor\",\n      \"version\": \"0.3.21\",\n      \"id\": \"futures-executor 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Executors for asynchronous tasks based on the futures-rs library.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-task\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-util\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"num_cpus\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.8.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures-executor\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.21/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"local_pool\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.21/tests/local_pool.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"thread_notify\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.21/benches/thread_notify.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"num_cpus\": [\n          \"dep:num_cpus\"\n        ],\n        \"std\": [\n          \"futures-core/std\",\n          \"futures-task/std\",\n          \"futures-util/std\"\n        ],\n        \"thread-pool\": [\n          \"std\",\n          \"num_cpus\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-executor-0.3.21/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/futures-rs\",\n      \"homepage\": \"https://rust-lang.github.io/futures-rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.45\"\n    },\n    {\n      \"name\": \"futures-intrusive\",\n      \"version\": \"0.4.0\",\n      \"id\": \"futures-intrusive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Futures based on intrusive data structures - for std and no-std environments.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lock_api\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"parking_lot\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-std\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crossbeam\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"async-await\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pin-utils\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"signal-hook\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.11\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.11\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"full\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures_intrusive\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cancellation\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/examples/cancellation.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"philosophers\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/examples/philosophers.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"timer\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/timer.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mutex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/mutex.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mpmc_channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/mpmc_channel.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"state_broadcast_channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/state_broadcast_channel.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"semaphore\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/semaphore.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"manual_reset_event\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/manual_reset_event.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"oneshot_channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/tests/oneshot_channel.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mpmc_channel\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/benches/mpmc_channel.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mutex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/benches/mutex.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"semaphore\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/benches/semaphore.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [\n          \"futures-core/alloc\"\n        ],\n        \"default\": [\n          \"std\"\n        ],\n        \"parking_lot\": [\n          \"dep:parking_lot\"\n        ],\n        \"std\": [\n          \"alloc\",\n          \"parking_lot\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-intrusive-0.4.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Matthias Einwag <matthias.einwag@live.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/Matthias247/futures-intrusive\",\n      \"homepage\": \"https://github.com/Matthias247/futures-intrusive\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"futures-sink\",\n      \"version\": \"0.3.21\",\n      \"id\": \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"The asynchronous `Sink` trait for the futures-rs library.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures-sink\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-sink-0.3.21/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"std\": [\n          \"alloc\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-sink-0.3.21/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/futures-rs\",\n      \"homepage\": \"https://rust-lang.github.io/futures-rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"futures-task\",\n      \"version\": \"0.3.21\",\n      \"id\": \"futures-task 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Tools for working with tasks.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures-task\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-task-0.3.21/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-task-0.3.21/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"cfg-target-has-atomic\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"std\": [\n          \"alloc\"\n        ],\n        \"unstable\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-task-0.3.21/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/futures-rs\",\n      \"homepage\": \"https://rust-lang.github.io/futures-rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.45\"\n    },\n    {\n      \"name\": \"futures-util\",\n      \"version\": \"0.3.21\",\n      \"id\": \"futures-util 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Common utilities and extension traits for the futures-rs library.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"futures-channel\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-io\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-macro\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-sink\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-task\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.25\",\n          \"kind\": null,\n          \"rename\": \"futures_01\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"memchr\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pin-project-lite\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pin-utils\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"slab\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-io\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.11\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"futures-util\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.21/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"futures_unordered\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.21/benches/futures_unordered.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"flatten_unordered\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.21/benches/flatten_unordered.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.21/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [\n          \"futures-core/alloc\",\n          \"futures-task/alloc\"\n        ],\n        \"async-await\": [],\n        \"async-await-macro\": [\n          \"async-await\",\n          \"futures-macro\"\n        ],\n        \"bilock\": [],\n        \"cfg-target-has-atomic\": [],\n        \"channel\": [\n          \"std\",\n          \"futures-channel\"\n        ],\n        \"compat\": [\n          \"std\",\n          \"futures_01\"\n        ],\n        \"default\": [\n          \"std\",\n          \"async-await\",\n          \"async-await-macro\"\n        ],\n        \"futures-channel\": [\n          \"dep:futures-channel\"\n        ],\n        \"futures-io\": [\n          \"dep:futures-io\"\n        ],\n        \"futures-macro\": [\n          \"dep:futures-macro\"\n        ],\n        \"futures-sink\": [\n          \"dep:futures-sink\"\n        ],\n        \"futures_01\": [\n          \"dep:futures_01\"\n        ],\n        \"io\": [\n          \"std\",\n          \"futures-io\",\n          \"memchr\"\n        ],\n        \"io-compat\": [\n          \"io\",\n          \"compat\",\n          \"tokio-io\"\n        ],\n        \"memchr\": [\n          \"dep:memchr\"\n        ],\n        \"sink\": [\n          \"futures-sink\"\n        ],\n        \"slab\": [\n          \"dep:slab\"\n        ],\n        \"std\": [\n          \"alloc\",\n          \"futures-core/std\",\n          \"futures-task/std\",\n          \"slab\"\n        ],\n        \"tokio-io\": [\n          \"dep:tokio-io\"\n        ],\n        \"unstable\": [\n          \"futures-core/unstable\",\n          \"futures-task/unstable\"\n        ],\n        \"write-all-vectored\": [\n          \"io\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.21/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/futures-rs\",\n      \"homepage\": \"https://rust-lang.github.io/futures-rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.45\"\n    },\n    {\n      \"name\": \"generic-array\",\n      \"version\": \"0.14.5\",\n      \"id\": \"generic-array 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Generic types implementing functionality of arrays\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"typenum\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.12\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bincode\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"version_check\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"generic_array\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/tests/iter.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"import_name\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/tests/import_name.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"hex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/tests/hex.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mod\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/tests/mod.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"generics\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/tests/generics.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"arr\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/tests/arr.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"more_lengths\": [],\n        \"serde\": [\n          \"dep:serde\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/generic-array-0.14.5/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Bartłomiej Kamiński <fizyk20@gmail.com>\",\n        \"Aaron Trent <novacrazy@gmail.com>\"\n      ],\n      \"categories\": [\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"generic\",\n        \"array\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/fizyk20/generic-array.git\",\n      \"homepage\": null,\n      \"documentation\": \"http://fizyk20.github.io/generic-array/generic_array/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"getrandom\",\n      \"version\": \"0.2.6\",\n      \"id\": \"getrandom 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A small cross-platform library for retrieving random data from system source\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"js-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.62\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.18\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.10\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_os = \\\"wasi\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.120\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"getrandom\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.6/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"normal\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.6/tests/normal.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"custom\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.6/tests/custom.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rdrand\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.6/tests/rdrand.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mod\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.6/benches/mod.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"custom\": [],\n        \"js\": [\n          \"wasm-bindgen\",\n          \"js-sys\"\n        ],\n        \"js-sys\": [\n          \"dep:js-sys\"\n        ],\n        \"rdrand\": [],\n        \"rustc-dep-of-std\": [\n          \"compiler_builtins\",\n          \"core\",\n          \"libc/rustc-dep-of-std\",\n          \"wasi/rustc-dep-of-std\"\n        ],\n        \"std\": [],\n        \"test-in-browser\": [],\n        \"wasm-bindgen\": [\n          \"dep:wasm-bindgen\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/getrandom-0.2.6/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"std\",\n              \"custom\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The Rand Project Developers\"\n      ],\n      \"categories\": [\n        \"os\",\n        \"no-std\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-random/getrandom\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/getrandom\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"hashbrown\",\n      \"version\": \"0.11.2\",\n      \"id\": \"hashbrown 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/MIT\",\n      \"license_file\": null,\n      \"description\": \"A Rust port of Google's SwissTable hash map\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"ahash\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-alloc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": \"alloc\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bumpalo\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^3.5.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rayon\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.25\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"doc-comment\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"fnv\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"small_rng\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rayon\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"hashbrown\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"serde\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/tests/serde.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"set\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/tests/set.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rayon\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/tests/rayon.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"hasher\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/tests/hasher.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"ahash\": [\n          \"dep:ahash\"\n        ],\n        \"ahash-compile-time-rng\": [\n          \"ahash/compile-time-rng\"\n        ],\n        \"alloc\": [\n          \"dep:alloc\"\n        ],\n        \"bumpalo\": [\n          \"dep:bumpalo\"\n        ],\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"default\": [\n          \"ahash\",\n          \"inline-more\"\n        ],\n        \"inline-more\": [],\n        \"nightly\": [],\n        \"raw\": [],\n        \"rayon\": [\n          \"dep:rayon\"\n        ],\n        \"rustc-dep-of-std\": [\n          \"nightly\",\n          \"core\",\n          \"compiler_builtins\",\n          \"alloc\",\n          \"rustc-internal-api\"\n        ],\n        \"rustc-internal-api\": [],\n        \"serde\": [\n          \"dep:serde\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashbrown-0.11.2/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"nightly\",\n              \"rayon\",\n              \"serde\",\n              \"raw\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Amanieu d'Antras <amanieu@gmail.com>\"\n      ],\n      \"categories\": [\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"hash\",\n        \"no_std\",\n        \"hashmap\",\n        \"swisstable\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/hashbrown\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"hashlink\",\n      \"version\": \"0.7.0\",\n      \"id\": \"hashlink 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"HashMap-like containers that hold their key-value pairs in a user controllable order\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"hashbrown\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"fxhash\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"hashlink\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashlink-0.7.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"linked_hash_set\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashlink-0.7.0/tests/linked_hash_set.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"serde\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashlink-0.7.0/tests/serde.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lru_cache\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashlink-0.7.0/tests/lru_cache.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"linked_hash_map\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashlink-0.7.0/tests/linked_hash_map.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"serde_impl\": [\n          \"serde\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hashlink-0.7.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"kyren <kerriganw@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"data-structures\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/kyren/hashlink\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/hashlink\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"heck\",\n      \"version\": \"0.3.3\",\n      \"id\": \"heck 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"heck is a case conversion library.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"unicode-segmentation\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"heck\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.3/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/heck-0.3.3/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Without Boats <woboats@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"string\",\n        \"case\",\n        \"camel\",\n        \"snake\",\n        \"unicode\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/withoutboats/heck\",\n      \"homepage\": \"https://github.com/withoutboats/heck\",\n      \"documentation\": \"https://docs.rs/heck\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"hermit-abi\",\n      \"version\": \"0.1.19\",\n      \"id\": \"hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"hermit-abi is small interface to call functions from the unikernel RustyHermit.\\nIt is used to build the target `x86_64-unknown-hermit`.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.51\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"hermit-abi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hermit-abi-0.1.19/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"default\": [],\n        \"docs\": [],\n        \"rustc-dep-of-std\": [\n          \"core\",\n          \"compiler_builtins/rustc-dep-of-std\",\n          \"libc/rustc-dep-of-std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hermit-abi-0.1.19/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"default-target\": \"x86_64-unknown-hermit\",\n            \"features\": [\n              \"docs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Stefan Lankes\"\n      ],\n      \"categories\": [\n        \"os\"\n      ],\n      \"keywords\": [\n        \"unikernel\",\n        \"libos\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/hermitcore/libhermit-rs\",\n      \"homepage\": null,\n      \"documentation\": \"https://hermitcore.github.io/rusty-hermit/hermit_abi\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"hex\",\n      \"version\": \"0.4.3\",\n      \"id\": \"hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Encoding and decoding data into/from hexadecimal representation.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"faster-hex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pretty_assertions\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-hex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"version-sync\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"hex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hex-0.4.3/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"version-number\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hex-0.4.3/tests/version-number.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"serde\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hex-0.4.3/tests/serde.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"hex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hex-0.4.3/benches/hex.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": [\n          \"alloc\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/hex-0.4.3/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"KokaKiwi <kokakiwi@kokakiwi.net>\"\n      ],\n      \"categories\": [\n        \"encoding\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"no_std\",\n        \"hex\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/KokaKiwi/rust-hex\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/hex/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"idna\",\n      \"version\": \"0.2.3\",\n      \"id\": \"idna 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"IDNA (Internationalizing Domain Names in Applications) and Punycode.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"matches\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"unicode-bidi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"unicode-normalization\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.17\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"assert_matches\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bencher\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"idna\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/idna-0.2.3/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/idna-0.2.3/tests/tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unit\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/idna-0.2.3/tests/unit.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"all\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/idna-0.2.3/benches/all.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/idna-0.2.3/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The rust-url developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/servo/rust-url/\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"indexmap\",\n      \"version\": \"1.8.1\",\n      \"id\": \"indexmap 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/MIT\",\n      \"license_file\": null,\n      \"description\": \"A hash table with consistent order and fast iteration.\\n\\nThe indexmap is a hash table where the iteration order of the key-value\\npairs is independent of the hash values of the keys. It has the usual\\nhash table functionality, it preserves insertion order except after\\nremovals, and it allows lookup of its elements by either hash table key\\nor numerical index. A corresponding hash set type is also provided.\\n\\nThis crate was initially published under the name ordermap, but it was renamed to\\nindexmap.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"hashbrown\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"raw\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rayon\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-rayon\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"fnv\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"fxhash\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"itertools\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.10\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quickcheck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"small_rng\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_derive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"autocfg\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"indexmap\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"equivalent_trait\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/tests/equivalent_trait.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/tests/tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_full_path\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/tests/macros_full_path.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"quick\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/tests/quick.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"faststring\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/benches/faststring.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"rayon\": [\n          \"dep:rayon\"\n        ],\n        \"rustc-rayon\": [\n          \"dep:rustc-rayon\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"serde-1\": [\n          \"serde\"\n        ],\n        \"std\": [],\n        \"test_debug\": [],\n        \"test_low_transition_point\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/indexmap-1.8.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"serde-1\",\n              \"rayon\"\n            ]\n          }\n        },\n        \"release\": {\n          \"no-dev-version\": true,\n          \"tag-name\": \"{{version}}\"\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"bluss\",\n        \"Josh Stone <cuviper@gmail.com>\"\n      ],\n      \"categories\": [\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"hashmap\",\n        \"no_std\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/bluss/indexmap\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/indexmap/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"instant\",\n      \"version\": \"0.1.12\",\n      \"id\": \"instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"BSD-3-Clause\",\n      \"license_file\": null,\n      \"description\": \"A partial replacement for std::time::Instant that works on WASM too.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"js-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"asmjs-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"stdweb\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"asmjs-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": null,\n          \"rename\": \"wasm-bindgen_rs\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"asmjs-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"web-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"Window\",\n            \"Performance\",\n            \"PerformanceTiming\"\n          ],\n          \"target\": \"asmjs-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"js-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"wasm32-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"stdweb\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"wasm32-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": null,\n          \"rename\": \"wasm-bindgen_rs\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"wasm32-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"web-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"Window\",\n            \"Performance\",\n            \"PerformanceTiming\"\n          ],\n          \"target\": \"wasm32-unknown-emscripten\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"js-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"wasm32-unknown-unknown\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"stdweb\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"wasm32-unknown-unknown\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": null,\n          \"rename\": \"wasm-bindgen_rs\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"wasm32-unknown-unknown\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"web-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"Window\",\n            \"Performance\",\n            \"PerformanceTiming\"\n          ],\n          \"target\": \"wasm32-unknown-unknown\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"instant\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/instant-0.1.12/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"wasm\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/instant-0.1.12/tests/wasm.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"inaccurate\": [],\n        \"js-sys\": [\n          \"dep:js-sys\"\n        ],\n        \"now\": [],\n        \"stdweb\": [\n          \"dep:stdweb\"\n        ],\n        \"wasm-bindgen\": [\n          \"js-sys\",\n          \"wasm-bindgen_rs\",\n          \"web-sys\"\n        ],\n        \"wasm-bindgen_rs\": [\n          \"dep:wasm-bindgen_rs\"\n        ],\n        \"web-sys\": [\n          \"dep:web-sys\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/instant-0.1.12/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"sebcrozet <developer@crozet.re>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"time\",\n        \"wasm\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/sebcrozet/instant\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"itertools\",\n      \"version\": \"0.10.3\",\n      \"id\": \"itertools 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Extra iterator adaptors, iterator methods, free functions, and macros.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"either\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"paste\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"permutohedron\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quickcheck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"itertools\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"iris\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/examples/iris.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tuples\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/tuples.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"specializations\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/specializations.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"peeking_take_while\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/peeking_take_while.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_core\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/test_core.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"quick\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/quick.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_std\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/test_std.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"adaptors_no_collect\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/adaptors_no_collect.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_hygiene\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/macros_hygiene.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"zip\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/zip.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"merge_join\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/merge_join.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"flatten_ok\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/tests/flatten_ok.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tuple_combinations\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/tuple_combinations.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tuples\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/tuples.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fold_specialization\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/fold_specialization.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"combinations_with_replacement\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/combinations_with_replacement.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tree_fold1\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/tree_fold1.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench1\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/bench1.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"combinations\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/combinations.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"powerset\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/benches/powerset.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"use_std\"\n        ],\n        \"use_alloc\": [],\n        \"use_std\": [\n          \"use_alloc\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itertools-0.10.3/Cargo.toml\",\n      \"metadata\": {\n        \"release\": {\n          \"no-dev-version\": true\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"bluss\"\n      ],\n      \"categories\": [\n        \"algorithms\",\n        \"rust-patterns\"\n      ],\n      \"keywords\": [\n        \"iterator\",\n        \"data-structure\",\n        \"zip\",\n        \"product\",\n        \"group-by\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-itertools/itertools\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/itertools/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"itoa\",\n      \"version\": \"1.0.1\",\n      \"id\": \"itoa 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Fast integer primitive to string conversion\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"itoa\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itoa-1.0.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itoa-1.0.1/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itoa-1.0.1/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/itoa-1.0.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"value-formatting\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/itoa\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/itoa\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"js-sys\",\n      \"version\": \"0.3.57\",\n      \"id\": \"js-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Bindings for all JS global objects and functions in all JS environments like\\nNode.js and browsers, built on `#[wasm_bindgen]` using the `wasm-bindgen` crate.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.3.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"js-sys\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/js-sys-0.3.57/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"headless\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/js-sys-0.3.57/tests/headless.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"wasm\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/js-sys-0.3.57/tests/wasm/main.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/js-sys-0.3.57/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [\n        \"wasm\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"./README.md\",\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen/tree/master/crates/js-sys\",\n      \"homepage\": \"https://rustwasm.github.io/wasm-bindgen/\",\n      \"documentation\": \"https://docs.rs/js-sys\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"lazy_static\",\n      \"version\": \"1.4.0\",\n      \"id\": \"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A macro for declaring lazily evaluated statics in Rust.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"spin\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"doc-comment\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"lazy_static\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"no_std\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/tests/no_std.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/tests/test.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"spin\": [\n          \"dep:spin\"\n        ],\n        \"spin_no_std\": [\n          \"spin\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lazy_static-1.4.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Marvin Löbel <loebel.marvin@gmail.com>\"\n      ],\n      \"categories\": [\n        \"no-std\",\n        \"rust-patterns\",\n        \"memory-management\"\n      ],\n      \"keywords\": [\n        \"macro\",\n        \"lazy\",\n        \"static\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang-nursery/lazy-static.rs\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/lazy_static\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"libc\",\n      \"version\": \"0.2.122\",\n      \"id\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Raw FFI bindings to platform libraries like libc.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"libc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.122/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"const_fn\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.122/tests/const_fn.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.122/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"align\": [],\n        \"const-extern-fn\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"extra_traits\": [],\n        \"rustc-dep-of-std\": [\n          \"align\",\n          \"rustc-std-workspace-core\"\n        ],\n        \"rustc-std-workspace-core\": [\n          \"dep:rustc-std-workspace-core\"\n        ],\n        \"std\": [],\n        \"use_std\": [\n          \"std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.122/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"const-extern-fn\",\n              \"extra_traits\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The Rust Project Developers\"\n      ],\n      \"categories\": [\n        \"external-ffi-bindings\",\n        \"no-std\",\n        \"os\"\n      ],\n      \"keywords\": [\n        \"libc\",\n        \"ffi\",\n        \"bindings\",\n        \"operating\",\n        \"system\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/libc\",\n      \"homepage\": \"https://github.com/rust-lang/libc\",\n      \"documentation\": \"https://docs.rs/libc/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"libsqlite3-sys\",\n      \"version\": \"0.23.2\",\n      \"id\": \"libsqlite3-sys 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Native bindings to the libsqlite3 library\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"openssl-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.59\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"runtime\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"cc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pkg-config\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.19\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"vcpkg\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"libsqlite3-sys\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libsqlite3-sys-0.23.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libsqlite3-sys-0.23.2/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"bindgen\": [\n          \"dep:bindgen\"\n        ],\n        \"buildtime_bindgen\": [\n          \"bindgen\",\n          \"pkg-config\",\n          \"vcpkg\"\n        ],\n        \"bundled\": [\n          \"cc\",\n          \"bundled_bindings\"\n        ],\n        \"bundled-sqlcipher\": [\n          \"bundled\"\n        ],\n        \"bundled-sqlcipher-vendored-openssl\": [\n          \"bundled-sqlcipher\",\n          \"openssl-sys/vendored\"\n        ],\n        \"bundled-windows\": [\n          \"cc\",\n          \"bundled_bindings\"\n        ],\n        \"bundled_bindings\": [],\n        \"cc\": [\n          \"dep:cc\"\n        ],\n        \"default\": [\n          \"min_sqlite_version_3_6_8\"\n        ],\n        \"in_gecko\": [],\n        \"min_sqlite_version_3_6_23\": [\n          \"pkg-config\",\n          \"vcpkg\"\n        ],\n        \"min_sqlite_version_3_6_8\": [\n          \"pkg-config\",\n          \"vcpkg\"\n        ],\n        \"min_sqlite_version_3_7_16\": [\n          \"pkg-config\",\n          \"vcpkg\"\n        ],\n        \"min_sqlite_version_3_7_7\": [\n          \"pkg-config\",\n          \"vcpkg\"\n        ],\n        \"openssl-sys\": [\n          \"dep:openssl-sys\"\n        ],\n        \"pkg-config\": [\n          \"dep:pkg-config\"\n        ],\n        \"preupdate_hook\": [\n          \"buildtime_bindgen\"\n        ],\n        \"session\": [\n          \"preupdate_hook\",\n          \"buildtime_bindgen\"\n        ],\n        \"sqlcipher\": [],\n        \"unlock_notify\": [],\n        \"vcpkg\": [\n          \"dep:vcpkg\"\n        ],\n        \"wasm32-wasi-vfs\": [],\n        \"winsqlite3\": [\n          \"min_sqlite_version_3_7_16\"\n        ],\n        \"with-asan\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/libsqlite3-sys-0.23.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The rusqlite developers\"\n      ],\n      \"categories\": [\n        \"external-ffi-bindings\"\n      ],\n      \"keywords\": [\n        \"sqlite\",\n        \"sqlcipher\",\n        \"ffi\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rusqlite/rusqlite\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": \"sqlite3\",\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"lock_api\",\n      \"version\": \"0.4.7\",\n      \"id\": \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Wrappers to create fully-featured Mutex and RwLock types. Compatible with no_std.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"owning_ref\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"scopeguard\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.126\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"autocfg\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.0\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"lock_api\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lock_api-0.4.7/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lock_api-0.4.7/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"arc_lock\": [],\n        \"nightly\": [],\n        \"owning_ref\": [\n          \"dep:owning_ref\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/lock_api-0.4.7/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Amanieu d'Antras <amanieu@gmail.com>\"\n      ],\n      \"categories\": [\n        \"concurrency\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"mutex\",\n        \"rwlock\",\n        \"lock\",\n        \"no_std\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/Amanieu/parking_lot\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"log\",\n      \"version\": \"0.4.16\",\n      \"id\": \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A lightweight logging facade for Rust\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sval\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.0-alpha.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"value-bag\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.0-alpha.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sval\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.0-alpha.5\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"value-bag\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.0-alpha.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"test\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"log\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.16/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"filters\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.16/tests/filters.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.16/tests/macros.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"value\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.16/benches/value.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.16/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"kv_unstable\": [\n          \"value-bag\"\n        ],\n        \"kv_unstable_serde\": [\n          \"kv_unstable_std\",\n          \"value-bag/serde\",\n          \"serde\"\n        ],\n        \"kv_unstable_std\": [\n          \"std\",\n          \"kv_unstable\",\n          \"value-bag/error\"\n        ],\n        \"kv_unstable_sval\": [\n          \"kv_unstable\",\n          \"value-bag/sval\",\n          \"sval\"\n        ],\n        \"max_level_debug\": [],\n        \"max_level_error\": [],\n        \"max_level_info\": [],\n        \"max_level_off\": [],\n        \"max_level_trace\": [],\n        \"max_level_warn\": [],\n        \"release_max_level_debug\": [],\n        \"release_max_level_error\": [],\n        \"release_max_level_info\": [],\n        \"release_max_level_off\": [],\n        \"release_max_level_trace\": [],\n        \"release_max_level_warn\": [],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": [],\n        \"sval\": [\n          \"dep:sval\"\n        ],\n        \"value-bag\": [\n          \"dep:value-bag\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/log-0.4.16/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"std\",\n              \"serde\",\n              \"kv_unstable_std\",\n              \"kv_unstable_sval\",\n              \"kv_unstable_serde\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The Rust Project Developers\"\n      ],\n      \"categories\": [\n        \"development-tools::debugging\"\n      ],\n      \"keywords\": [\n        \"logging\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/log\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/log\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"matches\",\n      \"version\": \"0.1.9\",\n      \"id\": \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"A macro to evaluate, as a boolean, whether an expression matches a pattern.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"matches\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/matches-0.1.9/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macro_use_one\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/matches-0.1.9/tests/macro_use_one.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"use_star\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/matches-0.1.9/tests/use_star.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/matches-0.1.9/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Simon Sapin <simon.sapin@exyr.org>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/SimonSapin/rust-std-candidates\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/matches/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"memchr\",\n      \"version\": \"2.4.1\",\n      \"id\": \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Unlicense/MIT\",\n      \"license_file\": null,\n      \"description\": \"Safe interface to memchr.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.18\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quickcheck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"memchr\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.4.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.4.1/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"default\": [\n          \"std\"\n        ],\n        \"libc\": [\n          \"dep:libc\"\n        ],\n        \"rustc-dep-of-std\": [\n          \"core\",\n          \"compiler_builtins\"\n        ],\n        \"std\": [],\n        \"use_std\": [\n          \"std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.4.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Andrew Gallant <jamslam@gmail.com>\",\n        \"bluss\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"memchr\",\n        \"char\",\n        \"scan\",\n        \"strchr\",\n        \"string\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/BurntSushi/memchr\",\n      \"homepage\": \"https://github.com/BurntSushi/memchr\",\n      \"documentation\": \"https://docs.rs/memchr/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"minimal-lexical\",\n      \"version\": \"0.2.1\",\n      \"id\": \"minimal-lexical 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Fast float parsing conversion routines.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"minimal-lexical\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"libm_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/libm_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"number_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/number_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"vec_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/vec_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rounding_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/rounding_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bellerophon\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/bellerophon.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"slow_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/slow_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"parse_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/parse_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mask_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/mask_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lemire_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/lemire_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"integration_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/integration_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stackvec\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/stackvec.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bellerophon_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/tests/bellerophon_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"compact\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"lint\": [],\n        \"nightly\": [],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/minimal-lexical-0.2.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Alex Huszagh <ahuszagh@gmail.com>\"\n      ],\n      \"categories\": [\n        \"parsing\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"parsing\",\n        \"no_std\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/Alexhuszagh/minimal-lexical\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/minimal-lexical\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"mio\",\n      \"version\": \"0.8.2\",\n      \"id\": \"mio 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Lightweight non-blocking IO\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"log\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"env_logger\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.86\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_os = \\\"wasi\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_os = \\\"wasi\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.86\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"miow\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.6\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"ntapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"winsock2\",\n            \"mswsock\"\n          ],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"mio\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/mio-0.8.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_server\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/mio-0.8.2/examples/tcp_server.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"os-poll\",\n            \"net\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_listenfd_server\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/mio-0.8.2/examples/tcp_listenfd_server.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"os-poll\",\n            \"net\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"udp_server\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/mio-0.8.2/examples/udp_server.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"os-poll\",\n            \"net\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [],\n        \"net\": [],\n        \"os-ext\": [\n          \"os-poll\"\n        ],\n        \"os-poll\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/mio-0.8.2/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ],\n            \"targets\": [\n              \"aarch64-apple-ios\",\n              \"aarch64-linux-android\",\n              \"x86_64-apple-darwin\",\n              \"x86_64-pc-windows-msvc\",\n              \"x86_64-unknown-dragonfly\",\n              \"x86_64-unknown-freebsd\",\n              \"x86_64-unknown-illumos\",\n              \"x86_64-unknown-linux-gnu\",\n              \"x86_64-unknown-netbsd\",\n              \"x86_64-unknown-openbsd\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"os-poll\",\n            \"os-ext\",\n            \"net\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Carl Lerche <me@carllerche.com>\",\n        \"Thomas de Zeeuw <thomasdezeeuw@gmail.com>\",\n        \"Tokio Contributors <team@tokio.rs>\"\n      ],\n      \"categories\": [\n        \"asynchronous\"\n      ],\n      \"keywords\": [\n        \"io\",\n        \"async\",\n        \"non-blocking\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/tokio-rs/mio\",\n      \"homepage\": \"https://github.com/tokio-rs/mio\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"miow\",\n      \"version\": \"0.3.7\",\n      \"id\": \"miow 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A zero overhead I/O library for Windows, focusing on IOCP and Async I/O\\nabstractions.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"std\",\n            \"fileapi\",\n            \"handleapi\",\n            \"ioapiset\",\n            \"minwindef\",\n            \"namedpipeapi\",\n            \"ntdef\",\n            \"synchapi\",\n            \"winerror\",\n            \"winsock2\",\n            \"ws2def\",\n            \"ws2ipdef\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"socket2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"miow\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/miow-0.3.7/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/miow-0.3.7/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"default-target\": \"x86_64-pc-windows-msvc\",\n            \"targets\": [\n              \"aarch64-pc-windows-msvc\",\n              \"i686-pc-windows-msvc\",\n              \"x86_64-pc-windows-msvc\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Alex Crichton <alex@alexcrichton.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"iocp\",\n        \"windows\",\n        \"io\",\n        \"overlapped\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/yoshuawuyts/miow\",\n      \"homepage\": \"https://github.com/yoshuawuyts/miow\",\n      \"documentation\": \"https://docs.rs/miow/0.3/x86_64-pc-windows-msvc/miow/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"nom\",\n      \"version\": \"7.1.1\",\n      \"id\": \"nom 7.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"A byte-oriented, zero-copy, parser combinators library\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"memchr\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"minimal-lexical\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"doc-comment\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"proptest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"nom\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"json\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/examples/json.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"iterator\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/examples/iterator.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"s_expression\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/examples/s_expression.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"string\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/examples/string.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"arithmetic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/arithmetic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"arithmetic_ast\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/arithmetic_ast.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"css\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/css.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"custom_errors\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/custom_errors.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"float\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/float.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ini\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/ini.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ini_str\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/ini_str.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"issues\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/issues.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"json\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/json.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mp4\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/mp4.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"multiline\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/multiline.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"overflow\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/overflow.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"reborrow_fold\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/reborrow_fold.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fnmut\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/fnmut.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"escaped\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/tests/escaped.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"docsrs\": [],\n        \"std\": [\n          \"alloc\",\n          \"memchr/std\",\n          \"minimal-lexical/std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/nom-7.1.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"features\": [\n              \"alloc\",\n              \"std\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"contact@geoffroycouprie.com\"\n      ],\n      \"categories\": [\n        \"parsing\"\n      ],\n      \"keywords\": [\n        \"parser\",\n        \"parser-combinators\",\n        \"parsing\",\n        \"streaming\",\n        \"bit\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/Geal/nom\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/nom\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.48\"\n    },\n    {\n      \"name\": \"ntapi\",\n      \"version\": \"0.3.7\",\n      \"id\": \"ntapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"FFI bindings for Native API\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"cfg\",\n            \"evntrace\",\n            \"in6addr\",\n            \"inaddr\",\n            \"minwinbase\",\n            \"ntsecapi\",\n            \"windef\",\n            \"winioctl\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"ntapi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ntapi-0.3.7/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ntapi-0.3.7/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"beta\": [],\n        \"default\": [\n          \"user\"\n        ],\n        \"func-types\": [],\n        \"impl-default\": [\n          \"winapi/impl-default\"\n        ],\n        \"kernel\": [],\n        \"nightly\": [\n          \"beta\"\n        ],\n        \"user\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ntapi-0.3.7/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"default-target\": \"x86_64-pc-windows-msvc\",\n            \"features\": [\n              \"beta\"\n            ],\n            \"targets\": [\n              \"aarch64-pc-windows-msvc\",\n              \"i686-pc-windows-msvc\",\n              \"x86_64-pc-windows-msvc\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"MSxDOS <melcodos@gmail.com>\"\n      ],\n      \"categories\": [\n        \"external-ffi-bindings\",\n        \"no-std\",\n        \"os::windows-apis\"\n      ],\n      \"keywords\": [\n        \"windows\",\n        \"ffi\",\n        \"ntapi\",\n        \"native\",\n        \"win32\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/MSxDOS/ntapi\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/ntapi/*/x86_64-pc-windows-msvc/ntapi/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"num-traits\",\n      \"version\": \"0.2.14\",\n      \"id\": \"num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Numeric traits for generic mathematics\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"libm\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"autocfg\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"num-traits\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cast\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/tests/cast.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"i128\": [],\n        \"libm\": [\n          \"dep:libm\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num-traits-0.2.14/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"std\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The Rust Project Developers\"\n      ],\n      \"categories\": [\n        \"algorithms\",\n        \"science\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"mathematics\",\n        \"numerics\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-num/num-traits\",\n      \"homepage\": \"https://github.com/rust-num/num-traits\",\n      \"documentation\": \"https://docs.rs/num-traits\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"num_cpus\",\n      \"version\": \"1.13.1\",\n      \"id\": \"num_cpus 1.13.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Get the number of CPUs on a machine.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"hermit-abi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"aarch64\\\"), target_os = \\\"hermit\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.26\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(not(windows))\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"num_cpus\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num_cpus-1.13.1/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"values\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num_cpus-1.13.1/examples/values.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/num_cpus-1.13.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Sean McArthur <sean@seanmonstar.com>\"\n      ],\n      \"categories\": [\n        \"hardware-support\"\n      ],\n      \"keywords\": [\n        \"cpu\",\n        \"cpus\",\n        \"cores\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/seanmonstar/num_cpus\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/num_cpus\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"once_cell\",\n      \"version\": \"1.10.0\",\n      \"id\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Single assignment cells and lazy values.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"atomic-polyfill\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"parking_lot\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.12\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crossbeam-utils\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"regex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.2.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"once_cell\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/bench.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench_acquire\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/bench_acquire.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench_vs_lazy_static\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/bench_vs_lazy_static.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lazy_static\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/lazy_static.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"reentrant_init_deadlocks\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/reentrant_init_deadlocks.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"regex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/regex.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_synchronization\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/examples/test_synchronization.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"it\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/tests/it.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"alloc\": [\n          \"race\"\n        ],\n        \"atomic-polyfill\": [\n          \"dep:atomic-polyfill\"\n        ],\n        \"default\": [\n          \"std\"\n        ],\n        \"parking_lot\": [\n          \"dep:parking_lot\"\n        ],\n        \"race\": [],\n        \"std\": [\n          \"alloc\"\n        ],\n        \"unstable\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/once_cell-1.10.0/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Aleksey Kladov <aleksey.kladov@gmail.com>\"\n      ],\n      \"categories\": [\n        \"rust-patterns\",\n        \"memory-management\"\n      ],\n      \"keywords\": [\n        \"lazy\",\n        \"static\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/matklad/once_cell\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/once_cell\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"opaque-debug\",\n      \"version\": \"0.3.0\",\n      \"id\": \"opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Macro for opaque Debug trait implementation\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"opaque-debug\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/opaque-debug-0.3.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mod\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/opaque-debug-0.3.0/tests/mod.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/opaque-debug-0.3.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"RustCrypto Developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/RustCrypto/utils\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/opaque-debug\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"parking_lot\",\n      \"version\": \"0.11.2\",\n      \"id\": \"parking_lot 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/MIT\",\n      \"license_file\": null,\n      \"description\": \"More compact and efficient implementations of the standard synchronization primitives.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"instant\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lock_api\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"parking_lot_core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bincode\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.3.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"parking_lot\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot-0.11.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"issue_203\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot-0.11.2/tests/issue_203.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"arc_lock\": [\n          \"lock_api/arc_lock\"\n        ],\n        \"deadlock_detection\": [\n          \"parking_lot_core/deadlock_detection\"\n        ],\n        \"default\": [],\n        \"nightly\": [\n          \"parking_lot_core/nightly\",\n          \"lock_api/nightly\"\n        ],\n        \"owning_ref\": [\n          \"lock_api/owning_ref\"\n        ],\n        \"send_guard\": [],\n        \"serde\": [\n          \"lock_api/serde\"\n        ],\n        \"stdweb\": [\n          \"instant/stdweb\"\n        ],\n        \"wasm-bindgen\": [\n          \"instant/wasm-bindgen\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot-0.11.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Amanieu d'Antras <amanieu@gmail.com>\"\n      ],\n      \"categories\": [\n        \"concurrency\"\n      ],\n      \"keywords\": [\n        \"mutex\",\n        \"condvar\",\n        \"rwlock\",\n        \"once\",\n        \"thread\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/Amanieu/parking_lot\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"parking_lot_core\",\n      \"version\": \"0.8.5\",\n      \"id\": \"parking_lot_core 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/MIT\",\n      \"license_file\": null,\n      \"description\": \"An advanced API for creating custom synchronization primitives.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"backtrace\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.60\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"instant\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"petgraph\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"smallvec\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.6.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"thread-id\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^4.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"redox_syscall\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_os = \\\"redox\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.95\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"winnt\",\n            \"ntstatus\",\n            \"minwindef\",\n            \"winerror\",\n            \"winbase\",\n            \"errhandlingapi\",\n            \"handleapi\"\n          ],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"parking_lot_core\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot_core-0.8.5/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot_core-0.8.5/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"backtrace\": [\n          \"dep:backtrace\"\n        ],\n        \"deadlock_detection\": [\n          \"petgraph\",\n          \"thread-id\",\n          \"backtrace\"\n        ],\n        \"nightly\": [],\n        \"petgraph\": [\n          \"dep:petgraph\"\n        ],\n        \"thread-id\": [\n          \"dep:thread-id\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/parking_lot_core-0.8.5/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Amanieu d'Antras <amanieu@gmail.com>\"\n      ],\n      \"categories\": [\n        \"concurrency\"\n      ],\n      \"keywords\": [\n        \"mutex\",\n        \"condvar\",\n        \"rwlock\",\n        \"once\",\n        \"thread\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/Amanieu/parking_lot\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"paste\",\n      \"version\": \"1.0.7\",\n      \"id\": \"paste 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Macros for all your token pasting needs\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"paste-test-suite\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.49\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"diff\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"proc-macro\"\n          ],\n          \"crate_types\": [\n            \"proc-macro\"\n          ],\n          \"name\": \"paste\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_attr\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/tests/test_attr.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_doc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/tests/test_doc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compiletest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/tests/compiletest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_expr\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/tests/test_expr.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_item\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/tests/test_item.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/paste-1.0.7/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"no-std\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/paste\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"percent-encoding\",\n      \"version\": \"2.1.0\",\n      \"id\": \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Percent encoding and decoding\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"percent-encoding\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/percent-encoding-2.1.0/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/percent-encoding-2.1.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The rust-url developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/servo/rust-url/\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"pin-project\",\n      \"version\": \"1.0.10\",\n      \"id\": \"pin-project 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"A crate for safe and ergonomic pin-projection.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"pin-project-internal\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.10\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"macrotest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"static_assertions\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.49\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"pin-project\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"not_unpin-expanded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/not_unpin-expanded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"pinned_drop\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/pinned_drop.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"pinned_drop-expanded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/pinned_drop-expanded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"project_replace\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/project_replace.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"not_unpin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/not_unpin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"project_replace-expanded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/project_replace-expanded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unsafe_unpin-expanded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/unsafe_unpin-expanded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"enum-default\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/enum-default.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"enum-default-expanded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/enum-default-expanded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unsafe_unpin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/unsafe_unpin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"struct-default\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/struct-default.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"struct-default-expanded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/examples/struct-default-expanded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"cfg\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/cfg.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"pinned_drop\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/pinned_drop.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"proper_unpin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/proper_unpin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"pin_project\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/pin_project.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"drop_order\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/drop_order.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compiletest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/compiletest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"expandtest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/expandtest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"repr_packed\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/repr_packed.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unsafe_unpin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/unsafe_unpin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lint\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/tests/lint.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-1.0.10/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [\n        \"no-std\",\n        \"rust-patterns\"\n      ],\n      \"keywords\": [\n        \"pin\",\n        \"macros\",\n        \"attribute\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/taiki-e/pin-project\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.37\"\n    },\n    {\n      \"name\": \"pin-project-internal\",\n      \"version\": \"1.0.10\",\n      \"id\": \"pin-project-internal 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"Implementation detail of the `pin-project` crate.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.56\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"full\",\n            \"visit-mut\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"proc-macro\"\n          ],\n          \"crate_types\": [\n            \"proc-macro\"\n          ],\n          \"name\": \"pin-project-internal\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-internal-1.0.10/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-internal-1.0.10/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [\n        \"no-std\",\n        \"rust-patterns\"\n      ],\n      \"keywords\": [\n        \"pin\",\n        \"macros\",\n        \"attribute\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/taiki-e/pin-project\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"pin-project-lite\",\n      \"version\": \"0.2.8\",\n      \"id\": \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"A lightweight version of pin-project written with declarative macros.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"macrotest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"static_assertions\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.49\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"pin-project-lite\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"proper_unpin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/tests/proper_unpin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"drop_order\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/tests/drop_order.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compiletest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/tests/compiletest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"expandtest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/tests/expandtest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lint\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/tests/lint.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-project-lite-0.2.8/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [],\n      \"categories\": [\n        \"no-std\",\n        \"rust-patterns\"\n      ],\n      \"keywords\": [\n        \"pin\",\n        \"macros\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/taiki-e/pin-project-lite\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.37\"\n    },\n    {\n      \"name\": \"pin-utils\",\n      \"version\": \"0.1.0\",\n      \"id\": \"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Utilities for pinning\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"pin-utils\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-utils-0.1.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stack_pin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-utils-0.1.0/tests/stack_pin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"projection\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-utils-0.1.0/tests/projection.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pin-utils-0.1.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Josef Brandl <mail@josefbrandl.de>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang-nursery/pin-utils\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/pin-utils\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"pkg-config\",\n      \"version\": \"0.3.25\",\n      \"id\": \"pkg-config 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A library to run the pkg-config system tool at build time in order to be used in\\nCargo build scripts.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"pkg-config\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pkg-config-0.3.25/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pkg-config-0.3.25/tests/test.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/pkg-config-0.3.25/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Alex Crichton <alex@alexcrichton.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"build-dependencies\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/pkg-config-rs\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/pkg-config\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"proc-macro2\",\n      \"version\": \"1.0.37\",\n      \"id\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A substitute implementation of the compiler's `proc_macro` API to decouple\\ntoken-based libraries from the procedural macro use case.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"unicode-xid\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"proc-macro2\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"features\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/tests/features.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_fmt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/tests/test_fmt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"marker\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/tests/marker.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"comments\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/tests/comments.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"proc-macro\"\n        ],\n        \"nightly\": [],\n        \"proc-macro\": [],\n        \"span-locations\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/proc-macro2-1.0.37/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"rustc-args\": [\n              \"--cfg\",\n              \"procmacro2_semver_exempt\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"procmacro2_semver_exempt\",\n              \"--cfg\",\n              \"doc_cfg\"\n            ],\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"span-locations\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\",\n        \"Alex Crichton <alex@alexcrichton.com>\"\n      ],\n      \"categories\": [\n        \"development-tools::procedural-macro-helpers\"\n      ],\n      \"keywords\": [\n        \"macros\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/proc-macro2\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/proc-macro2\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"quote\",\n      \"version\": \"1.0.17\",\n      \"id\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Quasi-quoting macro quote!(...)\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.36\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.52\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"diff\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"quote\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.17/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compiletest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.17/tests/compiletest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.17/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"proc-macro\"\n        ],\n        \"proc-macro\": [\n          \"proc-macro2/proc-macro\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/quote-1.0.17/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"development-tools::procedural-macro-helpers\"\n      ],\n      \"keywords\": [\n        \"syn\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/quote\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/quote/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"redox_syscall\",\n      \"version\": \"0.2.13\",\n      \"id\": \"redox_syscall 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"A Rust library to access raw Redox system calls\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"bitflags\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"syscall\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/redox_syscall-0.2.13/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/redox_syscall-0.2.13/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Jeremy Soller <jackpot51@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://gitlab.redox-os.org/redox-os/syscall\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/redox_syscall\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"ring\",\n      \"version\": \"0.16.20\",\n      \"id\": \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": null,\n      \"license_file\": \"LICENSE\",\n      \"description\": \"Safe, fast, small crypto using Rust.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"untrusted\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"cc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.62\",\n          \"kind\": \"build\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"web-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.37\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"Crypto\",\n            \"Window\"\n          ],\n          \"target\": \"cfg(all(target_arch = \\\"wasm32\\\", target_vendor = \\\"unknown\\\", target_os = \\\"unknown\\\", target_env = \\\"\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"spin\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\", all(any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\"), any(target_os = \\\"android\\\", target_os = \\\"fuchsia\\\", target_os = \\\"linux\\\"))))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.69\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.5.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": \"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.5.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": \"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"illumos\\\", target_os = \\\"netbsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"solaris\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.80\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(any(unix, windows))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.18\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"ntsecapi\",\n            \"wtypesbase\"\n          ],\n          \"target\": \"cfg(target_os = \\\"windows\\\")\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"ring\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signature_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/signature_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rsa_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/rsa_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"hmac_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/hmac_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"constant_time_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/constant_time_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"pbkdf2_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/pbkdf2_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ecdsa_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/ecdsa_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rand_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/rand_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"hkdf_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/hkdf_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"agreement_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/agreement_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"quic_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/quic_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"aead_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/aead_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"digest_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/digest_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ed25519_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/tests/ed25519_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"alloc\",\n          \"dev_urandom_fallback\"\n        ],\n        \"dev_urandom_fallback\": [\n          \"once_cell\"\n        ],\n        \"internal_benches\": [],\n        \"once_cell\": [\n          \"dep:once_cell\"\n        ],\n        \"slow_tests\": [],\n        \"std\": [\n          \"alloc\"\n        ],\n        \"test_logging\": [],\n        \"wasm32_c\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ring-0.16.20/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Brian Smith <brian@briansmith.org>\"\n      ],\n      \"categories\": [\n        \"cryptography\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"crypto\",\n        \"cryptography\",\n        \"rand\",\n        \"ECC\",\n        \"RSA\"\n      ],\n      \"readme\": \"doc/link-to-readme.md\",\n      \"repository\": \"https://github.com/briansmith/ring\",\n      \"homepage\": null,\n      \"documentation\": \"https://briansmith.org/rustdoc/ring/\",\n      \"edition\": \"2018\",\n      \"links\": \"ring-asm\",\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"rustls\",\n      \"version\": \"0.19.1\",\n      \"id\": \"rustls 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/ISC/MIT\",\n      \"license_file\": null,\n      \"description\": \"Rustls is a modern TLS library written in Rust.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"base64\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.13.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"log\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"ring\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.16.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sct\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"webpki\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"env_logger\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"log\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"webpki-roots\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"rustls\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bogo_shim\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/examples/internal/bogo_shim.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"dangerous_configuration\",\n            \"quic\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"trytls_shim\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/examples/internal/trytls_shim.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/examples/internal/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"simple_0rtt_client\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/examples/simple_0rtt_client.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"limitedclient\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/examples/limitedclient.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"simpleclient\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/examples/simpleclient.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"benchmarks\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/tests/benchmarks.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"api\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/tests/api.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"benchmarks\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/tests/benchmarks.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"dangerous_configuration\": [],\n        \"default\": [\n          \"logging\"\n        ],\n        \"log\": [\n          \"dep:log\"\n        ],\n        \"logging\": [\n          \"log\"\n        ],\n        \"quic\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/rustls-0.19.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Joseph Birr-Pixton <jpixton@gmail.com>\"\n      ],\n      \"categories\": [\n        \"network-programming\",\n        \"cryptography\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"../README.md\",\n      \"repository\": \"https://github.com/ctz/rustls\",\n      \"homepage\": \"https://github.com/ctz/rustls\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"ryu\",\n      \"version\": \"1.0.9\",\n      \"id\": \"ryu 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 OR BSL-1.0\",\n      \"license_file\": null,\n      \"description\": \"Fast floating point to string conversion\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"no-panic\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"num_cpus\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand_xorshift\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"ryu\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"upstream_benchmark\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/examples/upstream_benchmark.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"d2s_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/d2s_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"common_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/common_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"f2s_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/f2s_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"s2d_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/s2d_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"d2s_table_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/d2s_table_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"exhaustive\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/exhaustive.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"s2f_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/tests/s2f_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"no-panic\": [\n          \"dep:no-panic\"\n        ],\n        \"small\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/ryu-1.0.9/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"value-formatting\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/ryu\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/ryu\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"scopeguard\",\n      \"version\": \"1.1.0\",\n      \"id\": \"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A RAII scope guard that will run a given closure when it goes out of scope,\\neven if the code between panics (assuming unwinding panic).\\n\\nDefines the macros `defer!`, `defer_on_unwind!`, `defer_on_success!` as\\nshorthands for guards with one of the implemented strategies.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"scopeguard\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/scopeguard-1.1.0/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"readme\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/scopeguard-1.1.0/examples/readme.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"use_std\"\n        ],\n        \"use_std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/scopeguard-1.1.0/Cargo.toml\",\n      \"metadata\": {\n        \"release\": {\n          \"no-dev-version\": true\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"bluss\"\n      ],\n      \"categories\": [\n        \"rust-patterns\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"scope-guard\",\n        \"defer\",\n        \"panic\",\n        \"unwind\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/bluss/scopeguard\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/scopeguard/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"sct\",\n      \"version\": \"0.6.1\",\n      \"id\": \"sct 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0/ISC/MIT\",\n      \"license_file\": null,\n      \"description\": \"Certificate transparency SCT verification library\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"ring\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.16.20\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"untrusted\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"sct\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sct-0.6.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sct-0.6.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Joseph Birr-Pixton <jpixton@gmail.com>\"\n      ],\n      \"categories\": [\n        \"network-programming\",\n        \"cryptography\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/ctz/sct.rs\",\n      \"homepage\": \"https://github.com/ctz/sct.rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"serde\",\n      \"version\": \"1.0.136\",\n      \"id\": \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A generic serialization/deserialization framework\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"serde_derive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.136\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_derive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"serde\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.136/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.136/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"derive\": [\n          \"serde_derive\"\n        ],\n        \"rc\": [],\n        \"serde_derive\": [\n          \"dep:serde_derive\"\n        ],\n        \"std\": [],\n        \"unstable\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.136/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"derive\",\n            \"rc\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Erick Tryzelaar <erick.tryzelaar@gmail.com>\",\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"encoding\"\n      ],\n      \"keywords\": [\n        \"serde\",\n        \"serialization\",\n        \"no_std\"\n      ],\n      \"readme\": \"crates-io.md\",\n      \"repository\": \"https://github.com/serde-rs/serde\",\n      \"homepage\": \"https://serde.rs\",\n      \"documentation\": \"https://docs.serde.rs/serde/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.15\"\n    },\n    {\n      \"name\": \"serde_derive\",\n      \"version\": \"1.0.136\",\n      \"id\": \"serde_derive 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Macros 1.1 implementation of #[derive(Serialize, Deserialize)]\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.60\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"proc-macro\"\n          ],\n          \"crate_types\": [\n            \"proc-macro\"\n          ],\n          \"name\": \"serde_derive\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.136/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.136/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [],\n        \"deserialize_in_place\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_derive-1.0.136/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Erick Tryzelaar <erick.tryzelaar@gmail.com>\",\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"serde\",\n        \"serialization\",\n        \"no_std\"\n      ],\n      \"readme\": \"crates-io.md\",\n      \"repository\": \"https://github.com/serde-rs/serde\",\n      \"homepage\": \"https://serde.rs\",\n      \"documentation\": \"https://serde.rs/derive.html\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"serde_json\",\n      \"version\": \"1.0.79\",\n      \"id\": \"serde_json 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A JSON serialization file format\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"indexmap\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.5\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"itoa\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"ryu\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.100\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"automod\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"ref-cast\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_bytes\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_derive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_stacker\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.49\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"diff\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"serde_json\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"regression\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/regression.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/stream.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compiletest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/compiletest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"map\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/map.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lexical\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/lexical.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"debug\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/debug.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [\n          \"serde/alloc\"\n        ],\n        \"arbitrary_precision\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"float_roundtrip\": [],\n        \"indexmap\": [\n          \"dep:indexmap\"\n        ],\n        \"preserve_order\": [\n          \"indexmap\"\n        ],\n        \"raw_value\": [],\n        \"std\": [\n          \"serde/std\"\n        ],\n        \"unbounded_depth\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"raw_value\",\n              \"unbounded_depth\"\n            ],\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"raw_value\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Erick Tryzelaar <erick.tryzelaar@gmail.com>\",\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"encoding\"\n      ],\n      \"keywords\": [\n        \"json\",\n        \"serde\",\n        \"serialization\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/serde-rs/json\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.serde.rs/serde_json/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.36\"\n    },\n    {\n      \"name\": \"sha2\",\n      \"version\": \"0.9.9\",\n      \"id\": \"sha2 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Pure Rust implementation of the SHA-2 hash function family\\nincluding SHA-224, SHA-256, SHA-384, and SHA-512.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"block-buffer\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"digest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"opaque-debug\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sha2-asm\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"digest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"dev\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hex-literal\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"cpufeatures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"sha2\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sha512sum\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/examples/sha512sum.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sha256sum\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/examples/sha256sum.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"lib\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/tests/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sha512\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/benches/sha512.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sha256\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/benches/sha256.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"asm\": [\n          \"sha2-asm\"\n        ],\n        \"asm-aarch64\": [\n          \"asm\"\n        ],\n        \"compress\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"force-soft\": [],\n        \"sha2-asm\": [\n          \"dep:sha2-asm\"\n        ],\n        \"std\": [\n          \"digest/std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sha2-0.9.9/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"RustCrypto Developers\"\n      ],\n      \"categories\": [\n        \"cryptography\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"crypto\",\n        \"sha2\",\n        \"hash\",\n        \"digest\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/RustCrypto/hashes\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/sha2\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"slab\",\n      \"version\": \"0.4.6\",\n      \"id\": \"slab 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Pre-allocated storage for a uniform data type\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.95\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"alloc\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"slab\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/slab-0.4.6/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"serde\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/slab-0.4.6/tests/serde.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"slab\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/slab-0.4.6/tests/slab.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/slab-0.4.6/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Carl Lerche <me@carllerche.com>\"\n      ],\n      \"categories\": [\n        \"memory-management\",\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"slab\",\n        \"allocator\",\n        \"no_std\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/tokio-rs/slab\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"smallvec\",\n      \"version\": \"1.8.0\",\n      \"id\": \"smallvec 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"'Small vector' optimization: store up to a small number of items on the stack\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"arbitrary\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bincode\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"smallvec\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/smallvec-1.8.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macro\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/smallvec-1.8.0/tests/macro.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/smallvec-1.8.0/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"arbitrary\": [\n          \"dep:arbitrary\"\n        ],\n        \"const_generics\": [],\n        \"const_new\": [\n          \"const_generics\"\n        ],\n        \"may_dangle\": [],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"specialization\": [],\n        \"union\": [],\n        \"write\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/smallvec-1.8.0/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The Servo Project Developers\"\n      ],\n      \"categories\": [\n        \"data-structures\"\n      ],\n      \"keywords\": [\n        \"small\",\n        \"vec\",\n        \"vector\",\n        \"stack\",\n        \"no_std\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/servo/rust-smallvec\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/smallvec/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"socket2\",\n      \"version\": \"0.4.4\",\n      \"id\": \"socket2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Utilities for handling networking sockets with a maximal amount of configuration\\npossible intended.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.114\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"handleapi\",\n            \"ws2ipdef\",\n            \"ws2tcpip\"\n          ],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"socket2\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/socket2-0.4.4/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"all\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/socket2-0.4.4/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"all\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Alex Crichton <alex@alexcrichton.com>\",\n        \"Thomas de Zeeuw <thomasdezeeuw@gmail.com>\"\n      ],\n      \"categories\": [\n        \"api-bindings\",\n        \"network-programming\"\n      ],\n      \"keywords\": [\n        \"io\",\n        \"socket\",\n        \"network\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rust-lang/socket2\",\n      \"homepage\": \"https://github.com/rust-lang/socket2\",\n      \"documentation\": \"https://docs.rs/socket2\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"spin\",\n      \"version\": \"0.5.2\",\n      \"id\": \"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Synchronization primitives based on spinning.\\nThey may contain data, are usable without `std`,\\nand static initializers are available.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"spin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.5.2/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"debug\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.5.2/examples/debug.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.5.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Mathijs van de Nes <git@mathijs.vd-nes.nl>\",\n        \"John Ericson <git@JohnEricson.me>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"spinlock\",\n        \"mutex\",\n        \"rwlock\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/mvdnes/spin-rs.git\",\n      \"homepage\": null,\n      \"documentation\": \"https://mvdnes.github.io/rust-docs/spin-rs/spin/index.html\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"spin\",\n      \"version\": \"0.9.2\",\n      \"id\": \"spin 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Spin-based synchronization primitives\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"lock_api\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": \"lock_api_crate\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"spin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.9.2/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"example\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"debug\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.9.2/examples/debug.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"barrier\": [\n          \"mutex\"\n        ],\n        \"default\": [\n          \"lock_api\",\n          \"mutex\",\n          \"spin_mutex\",\n          \"rwlock\",\n          \"once\",\n          \"lazy\",\n          \"barrier\"\n        ],\n        \"lazy\": [\n          \"once\"\n        ],\n        \"lock_api\": [\n          \"lock_api_crate\"\n        ],\n        \"lock_api_crate\": [\n          \"dep:lock_api_crate\"\n        ],\n        \"mutex\": [],\n        \"once\": [],\n        \"rwlock\": [],\n        \"spin_mutex\": [\n          \"mutex\"\n        ],\n        \"std\": [],\n        \"ticket_mutex\": [\n          \"mutex\"\n        ],\n        \"use_ticket_mutex\": [\n          \"mutex\",\n          \"ticket_mutex\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/spin-0.9.2/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Mathijs van de Nes <git@mathijs.vd-nes.nl>\",\n        \"John Ericson <git@JohnEricson.me>\",\n        \"Joshua Barretto <joshua.s.barretto@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"spinlock\",\n        \"mutex\",\n        \"rwlock\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/mvdnes/spin-rs.git\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"sqlformat\",\n      \"version\": \"0.1.8\",\n      \"id\": \"sqlformat 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Formats whitespace in a SQL string to make it easier to read\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"itertools\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.10\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"nom\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^7.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"unicode_categories\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"indoc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"sqlformat\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlformat-0.1.8/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlformat-0.1.8/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlformat-0.1.8/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Josh Holmer <jholmer.in@gmail.com>\"\n      ],\n      \"categories\": [\n        \"development-tools\"\n      ],\n      \"keywords\": [\n        \"sql\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/shssoichiro/sqlformat-rs\",\n      \"homepage\": \"https://github.com/shssoichiro/sqlformat-rs\",\n      \"documentation\": \"https://docs.rs/sqlformat\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"sqlx\",\n      \"version\": \"0.5.11\",\n      \"id\": \"sqlx 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"🧰 The Rust SQL Toolkit. An async, pure Rust SQL crate featuring compile-time checked queries without a DSL. Supports PostgreSQL, MySQL, and SQLite.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"sqlx-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sqlx-macros\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"anyhow\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.52\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-std\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.10.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"attributes\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"dotenv\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.15.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"env_logger\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.19\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"paste\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.6\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand_xoshiro\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.132\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.73\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"time\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.27\",\n          \"kind\": \"dev\",\n          \"rename\": \"time_\",\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.15.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"full\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.53\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"url\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.2.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"sqlx\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"any\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/any/any.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"any\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"any-pool\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/any/pool.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"any\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"migrate-macro\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/migrate/macro.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"macros\",\n            \"migrate\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sqlite\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/sqlite/sqlite.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"sqlite\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sqlite-types\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/sqlite/types.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"sqlite\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sqlite-describe\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/sqlite/describe.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"sqlite\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sqlite-macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/sqlite/macros.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"sqlite\",\n            \"macros\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sqlite-derives\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/sqlite/derives.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"sqlite\",\n            \"macros\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mysql\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mysql/mysql.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mysql\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mysql-types\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mysql/types.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mysql\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mysql-describe\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mysql/describe.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mysql\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mysql-macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mysql/macros.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mysql\",\n            \"macros\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"postgres\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/postgres/postgres.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"postgres\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"postgres-types\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/postgres/types.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"postgres\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"postgres-describe\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/postgres/describe.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"postgres\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"postgres-macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/postgres/macros.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"postgres\",\n            \"macros\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"postgres-derives\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/postgres/derives.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"postgres\",\n            \"macros\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mssql\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mssql/mssql.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mssql\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mssql-types\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mssql/types.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mssql\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mssql-describe\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mssql/describe.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mssql\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"mssql-macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/mssql/macros.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"mssql\",\n            \"macros\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ui-tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/tests/ui-tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"_rt-actix\": [],\n        \"_rt-async-std\": [],\n        \"_rt-tokio\": [],\n        \"all\": [\n          \"tls\",\n          \"all-databases\",\n          \"all-types\"\n        ],\n        \"all-databases\": [\n          \"mysql\",\n          \"sqlite\",\n          \"postgres\",\n          \"mssql\",\n          \"any\"\n        ],\n        \"all-types\": [\n          \"bigdecimal\",\n          \"decimal\",\n          \"json\",\n          \"time\",\n          \"chrono\",\n          \"ipnetwork\",\n          \"mac_address\",\n          \"uuid\",\n          \"bit-vec\",\n          \"bstr\",\n          \"git2\"\n        ],\n        \"any\": [\n          \"sqlx-core/any\"\n        ],\n        \"bigdecimal\": [\n          \"sqlx-core/bigdecimal\",\n          \"sqlx-macros/bigdecimal\"\n        ],\n        \"bit-vec\": [\n          \"sqlx-core/bit-vec\",\n          \"sqlx-macros/bit-vec\"\n        ],\n        \"bstr\": [\n          \"sqlx-core/bstr\"\n        ],\n        \"chrono\": [\n          \"sqlx-core/chrono\",\n          \"sqlx-macros/chrono\"\n        ],\n        \"decimal\": [\n          \"sqlx-core/decimal\",\n          \"sqlx-macros/decimal\"\n        ],\n        \"default\": [\n          \"macros\",\n          \"migrate\"\n        ],\n        \"git2\": [\n          \"sqlx-core/git2\"\n        ],\n        \"ipnetwork\": [\n          \"sqlx-core/ipnetwork\",\n          \"sqlx-macros/ipnetwork\"\n        ],\n        \"json\": [\n          \"sqlx-core/json\",\n          \"sqlx-macros/json\"\n        ],\n        \"mac_address\": [\n          \"sqlx-core/mac_address\",\n          \"sqlx-macros/mac_address\"\n        ],\n        \"macros\": [\n          \"sqlx-macros\"\n        ],\n        \"migrate\": [\n          \"sqlx-macros/migrate\",\n          \"sqlx-core/migrate\"\n        ],\n        \"mssql\": [\n          \"sqlx-core/mssql\",\n          \"sqlx-macros/mssql\"\n        ],\n        \"mysql\": [\n          \"sqlx-core/mysql\",\n          \"sqlx-macros/mysql\"\n        ],\n        \"offline\": [\n          \"sqlx-macros/offline\",\n          \"sqlx-core/offline\"\n        ],\n        \"postgres\": [\n          \"sqlx-core/postgres\",\n          \"sqlx-macros/postgres\"\n        ],\n        \"runtime-actix\": [],\n        \"runtime-actix-native-tls\": [\n          \"sqlx-core/runtime-actix-native-tls\",\n          \"sqlx-macros/runtime-actix-native-tls\",\n          \"_rt-actix\"\n        ],\n        \"runtime-actix-rustls\": [\n          \"sqlx-core/runtime-actix-rustls\",\n          \"sqlx-macros/runtime-actix-rustls\",\n          \"_rt-actix\"\n        ],\n        \"runtime-async-std\": [],\n        \"runtime-async-std-native-tls\": [\n          \"sqlx-core/runtime-async-std-native-tls\",\n          \"sqlx-macros/runtime-async-std-native-tls\",\n          \"_rt-async-std\"\n        ],\n        \"runtime-async-std-rustls\": [\n          \"sqlx-core/runtime-async-std-rustls\",\n          \"sqlx-macros/runtime-async-std-rustls\",\n          \"_rt-async-std\"\n        ],\n        \"runtime-tokio\": [],\n        \"runtime-tokio-native-tls\": [\n          \"sqlx-core/runtime-tokio-native-tls\",\n          \"sqlx-macros/runtime-tokio-native-tls\",\n          \"_rt-tokio\"\n        ],\n        \"runtime-tokio-rustls\": [\n          \"sqlx-core/runtime-tokio-rustls\",\n          \"sqlx-macros/runtime-tokio-rustls\",\n          \"_rt-tokio\"\n        ],\n        \"sqlite\": [\n          \"sqlx-core/sqlite\",\n          \"sqlx-macros/sqlite\"\n        ],\n        \"sqlx-macros\": [\n          \"dep:sqlx-macros\"\n        ],\n        \"time\": [\n          \"sqlx-core/time\",\n          \"sqlx-macros/time\"\n        ],\n        \"tls\": [],\n        \"uuid\": [\n          \"sqlx-core/uuid\",\n          \"sqlx-macros/uuid\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-0.5.11/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"all\",\n              \"runtime-async-std-native-tls\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Ryan Leckey <leckey.ryan@gmail.com>\",\n        \"Austin Bonander <austin.bonander@gmail.com>\",\n        \"Chloe Ross <orangesnowfox@gmail.com>\",\n        \"Daniel Akhterov <akhterovd@gmail.com>\"\n      ],\n      \"categories\": [\n        \"database\",\n        \"asynchronous\"\n      ],\n      \"keywords\": [\n        \"database\",\n        \"async\",\n        \"postgres\",\n        \"mysql\",\n        \"sqlite\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/launchbadge/sqlx\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/sqlx\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"sqlx-core\",\n      \"version\": \"0.5.11\",\n      \"id\": \"sqlx-core 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Core of SQLx, the rust SQL toolkit. Not intended to be used directly.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"ahash\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.6\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"atoi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"base64\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.13.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bigdecimal\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.2\",\n          \"kind\": null,\n          \"rename\": \"bigdecimal_\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bit-vec\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bitflags\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.3.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bstr\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.17\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"byteorder\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bytes\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"chrono\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"clock\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"crossbeam-queue\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"digest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"dirs\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^4.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"either\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.6.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"encoding_rs\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.30\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"flume\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.10.9\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"async\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-channel\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"sink\",\n            \"alloc\",\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-executor\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-intrusive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-util\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"alloc\",\n            \"sink\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"generic-array\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.14.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"git2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.13.25\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hashlink\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hmac\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"indexmap\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.6.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"ipnetwork\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.17.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"itoa\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.112\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"libsqlite3-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.23.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"pkg-config\",\n            \"vcpkg\",\n            \"bundled\",\n            \"unlock_notify\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"log\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.14\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"mac_address\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"md-5\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"memchr\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.4.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"num-bigint\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.9.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"paste\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.6\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"percent-encoding\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\",\n            \"std_rng\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"regex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.5.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rsa\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rust_decimal\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.19.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.19.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"dangerous_configuration\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.132\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\",\n            \"rc\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.73\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"raw_value\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sha-1\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sha2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"smallvec\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.7.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sqlformat\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sqlx-rt\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"stringprep\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"thiserror\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.30\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"time\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.27\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-stream\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"fs\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"url\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.2.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"uuid\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"webpki\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"webpki-roots\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"whoami\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.2.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sqlx\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.11\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"postgres\",\n            \"sqlite\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"sqlx-core\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-core-0.5.11/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"_rt-actix\": [\n          \"tokio-stream\"\n        ],\n        \"_rt-async-std\": [],\n        \"_rt-tokio\": [\n          \"tokio-stream\"\n        ],\n        \"_tls-native-tls\": [],\n        \"_tls-rustls\": [\n          \"rustls\",\n          \"webpki\",\n          \"webpki-roots\"\n        ],\n        \"all-databases\": [\n          \"postgres\",\n          \"mysql\",\n          \"sqlite\",\n          \"mssql\",\n          \"any\"\n        ],\n        \"all-types\": [\n          \"chrono\",\n          \"time\",\n          \"bigdecimal\",\n          \"decimal\",\n          \"ipnetwork\",\n          \"mac_address\",\n          \"json\",\n          \"uuid\",\n          \"bit-vec\"\n        ],\n        \"any\": [],\n        \"base64\": [\n          \"dep:base64\"\n        ],\n        \"bigdecimal\": [\n          \"bigdecimal_\",\n          \"num-bigint\"\n        ],\n        \"bigdecimal_\": [\n          \"dep:bigdecimal_\"\n        ],\n        \"bit-vec\": [\n          \"dep:bit-vec\"\n        ],\n        \"bstr\": [\n          \"dep:bstr\"\n        ],\n        \"chrono\": [\n          \"dep:chrono\"\n        ],\n        \"crc\": [\n          \"dep:crc\"\n        ],\n        \"decimal\": [\n          \"rust_decimal\",\n          \"num-bigint\"\n        ],\n        \"default\": [\n          \"migrate\"\n        ],\n        \"digest\": [\n          \"dep:digest\"\n        ],\n        \"dirs\": [\n          \"dep:dirs\"\n        ],\n        \"encoding_rs\": [\n          \"dep:encoding_rs\"\n        ],\n        \"flume\": [\n          \"dep:flume\"\n        ],\n        \"futures-executor\": [\n          \"dep:futures-executor\"\n        ],\n        \"generic-array\": [\n          \"dep:generic-array\"\n        ],\n        \"git2\": [\n          \"dep:git2\"\n        ],\n        \"hmac\": [\n          \"dep:hmac\"\n        ],\n        \"ipnetwork\": [\n          \"dep:ipnetwork\"\n        ],\n        \"json\": [\n          \"serde\",\n          \"serde_json\"\n        ],\n        \"libsqlite3-sys\": [\n          \"dep:libsqlite3-sys\"\n        ],\n        \"mac_address\": [\n          \"dep:mac_address\"\n        ],\n        \"md-5\": [\n          \"dep:md-5\"\n        ],\n        \"migrate\": [\n          \"sha2\",\n          \"crc\"\n        ],\n        \"mssql\": [\n          \"uuid\",\n          \"encoding_rs\",\n          \"regex\"\n        ],\n        \"mysql\": [\n          \"sha-1\",\n          \"sha2\",\n          \"generic-array\",\n          \"num-bigint\",\n          \"digest\",\n          \"rand\",\n          \"rsa\"\n        ],\n        \"num-bigint\": [\n          \"dep:num-bigint\"\n        ],\n        \"offline\": [\n          \"serde\",\n          \"either/serde\"\n        ],\n        \"postgres\": [\n          \"md-5\",\n          \"sha2\",\n          \"base64\",\n          \"sha-1\",\n          \"rand\",\n          \"hmac\",\n          \"futures-channel/sink\",\n          \"futures-util/sink\",\n          \"json\",\n          \"dirs\",\n          \"whoami\"\n        ],\n        \"rand\": [\n          \"dep:rand\"\n        ],\n        \"regex\": [\n          \"dep:regex\"\n        ],\n        \"rsa\": [\n          \"dep:rsa\"\n        ],\n        \"runtime-actix-native-tls\": [\n          \"sqlx-rt/runtime-actix-native-tls\",\n          \"_tls-native-tls\",\n          \"_rt-actix\"\n        ],\n        \"runtime-actix-rustls\": [\n          \"sqlx-rt/runtime-actix-rustls\",\n          \"_tls-rustls\",\n          \"_rt-actix\"\n        ],\n        \"runtime-async-std-native-tls\": [\n          \"sqlx-rt/runtime-async-std-native-tls\",\n          \"_tls-native-tls\",\n          \"_rt-async-std\"\n        ],\n        \"runtime-async-std-rustls\": [\n          \"sqlx-rt/runtime-async-std-rustls\",\n          \"_tls-rustls\",\n          \"_rt-async-std\"\n        ],\n        \"runtime-tokio-native-tls\": [\n          \"sqlx-rt/runtime-tokio-native-tls\",\n          \"_tls-native-tls\",\n          \"_rt-tokio\"\n        ],\n        \"runtime-tokio-rustls\": [\n          \"sqlx-rt/runtime-tokio-rustls\",\n          \"_tls-rustls\",\n          \"_rt-tokio\"\n        ],\n        \"rust_decimal\": [\n          \"dep:rust_decimal\"\n        ],\n        \"rustls\": [\n          \"dep:rustls\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"serde_json\": [\n          \"dep:serde_json\"\n        ],\n        \"sha-1\": [\n          \"dep:sha-1\"\n        ],\n        \"sha2\": [\n          \"dep:sha2\"\n        ],\n        \"sqlite\": [\n          \"libsqlite3-sys\",\n          \"futures-executor\",\n          \"flume\"\n        ],\n        \"time\": [\n          \"dep:time\"\n        ],\n        \"tokio-stream\": [\n          \"dep:tokio-stream\"\n        ],\n        \"uuid\": [\n          \"dep:uuid\"\n        ],\n        \"webpki\": [\n          \"dep:webpki\"\n        ],\n        \"webpki-roots\": [\n          \"dep:webpki-roots\"\n        ],\n        \"whoami\": [\n          \"dep:whoami\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-core-0.5.11/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"all-databases\",\n              \"all-types\",\n              \"offline\",\n              \"runtime-async-std-native-tls\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Ryan Leckey <leckey.ryan@gmail.com>\",\n        \"Austin Bonander <austin.bonander@gmail.com>\",\n        \"Chloe Ross <orangesnowfox@gmail.com>\",\n        \"Daniel Akhterov <akhterovd@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/launchbadge/sqlx\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"sqlx-macros\",\n      \"version\": \"0.5.11\",\n      \"id\": \"sqlx-macros 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Macros for SQLx, the rust SQL toolkit. Not intended to be used directly.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"dotenv\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.15.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"either\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.6.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"heck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"hex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.9.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.36\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.14\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.132\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.73\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sha2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sqlx-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"sqlx-rt\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.11\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.84\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"full\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"url\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.2.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"proc-macro\"\n          ],\n          \"crate_types\": [\n            \"proc-macro\"\n          ],\n          \"name\": \"sqlx-macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-macros-0.5.11/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"_rt-actix\": [],\n        \"_rt-async-std\": [],\n        \"_rt-tokio\": [],\n        \"bigdecimal\": [\n          \"sqlx-core/bigdecimal\"\n        ],\n        \"bit-vec\": [\n          \"sqlx-core/bit-vec\"\n        ],\n        \"chrono\": [\n          \"sqlx-core/chrono\"\n        ],\n        \"decimal\": [\n          \"sqlx-core/decimal\"\n        ],\n        \"default\": [\n          \"runtime-async-std-native-tls\",\n          \"migrate\"\n        ],\n        \"hex\": [\n          \"dep:hex\"\n        ],\n        \"ipnetwork\": [\n          \"sqlx-core/ipnetwork\"\n        ],\n        \"json\": [\n          \"sqlx-core/json\",\n          \"serde_json\"\n        ],\n        \"mac_address\": [\n          \"sqlx-core/mac_address\"\n        ],\n        \"migrate\": [\n          \"sha2\",\n          \"sqlx-core/migrate\"\n        ],\n        \"mssql\": [\n          \"sqlx-core/mssql\"\n        ],\n        \"mysql\": [\n          \"sqlx-core/mysql\"\n        ],\n        \"offline\": [\n          \"sqlx-core/offline\",\n          \"hex\",\n          \"serde\",\n          \"serde_json\",\n          \"sha2\"\n        ],\n        \"postgres\": [\n          \"sqlx-core/postgres\"\n        ],\n        \"runtime-actix-native-tls\": [\n          \"sqlx-core/runtime-actix-native-tls\",\n          \"sqlx-rt/runtime-actix-native-tls\",\n          \"_rt-actix\"\n        ],\n        \"runtime-actix-rustls\": [\n          \"sqlx-core/runtime-actix-rustls\",\n          \"sqlx-rt/runtime-actix-rustls\",\n          \"_rt-actix\"\n        ],\n        \"runtime-async-std-native-tls\": [\n          \"sqlx-core/runtime-async-std-native-tls\",\n          \"sqlx-rt/runtime-async-std-native-tls\",\n          \"_rt-async-std\"\n        ],\n        \"runtime-async-std-rustls\": [\n          \"sqlx-core/runtime-async-std-rustls\",\n          \"sqlx-rt/runtime-async-std-rustls\",\n          \"_rt-async-std\"\n        ],\n        \"runtime-tokio-native-tls\": [\n          \"sqlx-core/runtime-tokio-native-tls\",\n          \"sqlx-rt/runtime-tokio-native-tls\",\n          \"_rt-tokio\"\n        ],\n        \"runtime-tokio-rustls\": [\n          \"sqlx-core/runtime-tokio-rustls\",\n          \"sqlx-rt/runtime-tokio-rustls\",\n          \"_rt-tokio\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"serde_json\": [\n          \"dep:serde_json\"\n        ],\n        \"sha2\": [\n          \"dep:sha2\"\n        ],\n        \"sqlite\": [\n          \"sqlx-core/sqlite\"\n        ],\n        \"time\": [\n          \"sqlx-core/time\"\n        ],\n        \"uuid\": [\n          \"sqlx-core/uuid\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-macros-0.5.11/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Ryan Leckey <leckey.ryan@gmail.com>\",\n        \"Austin Bonander <austin.bonander@gmail.com>\",\n        \"Chloe Ross <orangesnowfox@gmail.com>\",\n        \"Daniel Akhterov <akhterovd@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/launchbadge/sqlx\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"sqlx-rt\",\n      \"version\": \"0.5.11\",\n      \"id\": \"sqlx-rt 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Runtime abstraction used by SQLx, the Rust SQL toolkit. Not intended to be used directly.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"actix-rt\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-native-tls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-rustls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-std\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.7.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"unstable\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"native-tls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"fs\",\n            \"net\",\n            \"rt\",\n            \"rt-multi-thread\",\n            \"time\",\n            \"io-util\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-native-tls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-rustls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.22.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"sqlx-rt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-rt-0.5.11/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"_rt-actix\": [\n          \"actix-rt\",\n          \"tokio\",\n          \"once_cell\"\n        ],\n        \"_rt-async-std\": [\n          \"async-std\"\n        ],\n        \"_rt-tokio\": [\n          \"tokio\",\n          \"once_cell\"\n        ],\n        \"_tls-native-tls\": [\n          \"native-tls\"\n        ],\n        \"_tls-rustls\": [],\n        \"actix-rt\": [\n          \"dep:actix-rt\"\n        ],\n        \"async-native-tls\": [\n          \"dep:async-native-tls\"\n        ],\n        \"async-rustls\": [\n          \"dep:async-rustls\"\n        ],\n        \"async-std\": [\n          \"dep:async-std\"\n        ],\n        \"native-tls\": [\n          \"dep:native-tls\"\n        ],\n        \"once_cell\": [\n          \"dep:once_cell\"\n        ],\n        \"runtime-actix-native-tls\": [\n          \"_rt-actix\",\n          \"_tls-native-tls\",\n          \"tokio-native-tls\"\n        ],\n        \"runtime-actix-rustls\": [\n          \"_rt-actix\",\n          \"_tls-rustls\",\n          \"tokio-rustls\"\n        ],\n        \"runtime-async-std-native-tls\": [\n          \"_rt-async-std\",\n          \"_tls-native-tls\",\n          \"async-native-tls\"\n        ],\n        \"runtime-async-std-rustls\": [\n          \"_rt-async-std\",\n          \"_tls-rustls\",\n          \"async-rustls\"\n        ],\n        \"runtime-tokio-native-tls\": [\n          \"_rt-tokio\",\n          \"_tls-native-tls\",\n          \"tokio-native-tls\"\n        ],\n        \"runtime-tokio-rustls\": [\n          \"_rt-tokio\",\n          \"_tls-rustls\",\n          \"tokio-rustls\"\n        ],\n        \"tokio\": [\n          \"dep:tokio\"\n        ],\n        \"tokio-native-tls\": [\n          \"dep:tokio-native-tls\"\n        ],\n        \"tokio-rustls\": [\n          \"dep:tokio-rustls\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/sqlx-rt-0.5.11/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Ryan Leckey <leckey.ryan@gmail.com>\",\n        \"Austin Bonander <austin.bonander@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/launchbadge/sqlx\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"stringprep\",\n      \"version\": \"0.1.2\",\n      \"id\": \"stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"An implementation of the stringprep algorithm\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"unicode-bidi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"unicode-normalization\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"stringprep\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/stringprep-0.1.2/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"saslprep_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/stringprep-0.1.2/tests/saslprep_tests.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"nodeprep_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/stringprep-0.1.2/tests/nodeprep_tests.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"nameprep_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/stringprep-0.1.2/tests/nameprep_tests.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/stringprep-0.1.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Steven Fackler <sfackler@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/sfackler/rust-stringprep\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/stringprep/0.1.2/stringprep\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"syn\",\n      \"version\": \"1.0.91\",\n      \"id\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Parser for Rust source code\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.32\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"unicode-xid\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"anyhow\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"automod\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"flate2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"insta\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rayon\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"ref-cast\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"regex\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"reqwest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.11\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"blocking\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn-test-suite\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tar\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.16\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"termcolor\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"walkdir\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"syn\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"regression\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/regression.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_pat\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_pat.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_precedence\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_precedence.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_grouping\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_grouping.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_round_trip\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_round_trip.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_should_parse\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_should_parse.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_parse_stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_parse_stream.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_shebang\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_shebang.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_size\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_size.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_generics\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_generics.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"zzz_stable\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/zzz_stable.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_meta\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_meta.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_asyncness\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_asyncness.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_token_trees\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_token_trees.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_ty\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_ty.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_parse_buffer\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_parse_buffer.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_visibility\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_visibility.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_iterators\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_iterators.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_lit\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_lit.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_expr\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_expr.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_path\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_path.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_receiver\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_receiver.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_derive_input\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_derive_input.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_ident\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_ident.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_item\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_item.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_stmt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_stmt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_attribute\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/tests/test_attribute.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rust\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/benches/rust.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"full\",\n            \"parsing\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"file\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/benches/file.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"full\",\n            \"parsing\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"clone-impls\": [],\n        \"default\": [\n          \"derive\",\n          \"parsing\",\n          \"printing\",\n          \"clone-impls\",\n          \"proc-macro\"\n        ],\n        \"derive\": [],\n        \"extra-traits\": [],\n        \"fold\": [],\n        \"full\": [],\n        \"parsing\": [],\n        \"printing\": [\n          \"quote\"\n        ],\n        \"proc-macro\": [\n          \"proc-macro2/proc-macro\",\n          \"quote/proc-macro\"\n        ],\n        \"quote\": [\n          \"dep:quote\"\n        ],\n        \"test\": [\n          \"syn-test-suite/all-features\"\n        ],\n        \"visit\": [],\n        \"visit-mut\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.91/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"doc_cfg\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"full\",\n            \"visit\",\n            \"visit-mut\",\n            \"fold\",\n            \"extra-traits\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"development-tools::procedural-macro-helpers\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/syn\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/syn\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"thiserror\",\n      \"version\": \"1.0.30\",\n      \"id\": \"thiserror 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"derive(Error)\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"thiserror-impl\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=1.0.30\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"anyhow\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"ref-cast\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustversion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.49\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"diff\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"thiserror\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_display\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_display.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_backtrace\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_backtrace.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_transparent\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_transparent.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_from\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_from.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_error\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_error.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_generics\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_generics.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_source\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_source.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"compiletest\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/compiletest.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_lints\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_lints.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_expr\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_expr.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_path\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_path.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_option\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/tests/test_option.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-1.0.30/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [\n        \"rust-patterns\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/dtolnay/thiserror\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/thiserror\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"thiserror-impl\",\n      \"version\": \"1.0.30\",\n      \"id\": \"thiserror-impl 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Implementation detail of the `thiserror` crate\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.45\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"proc-macro\"\n          ],\n          \"crate_types\": [\n            \"proc-macro\"\n          ],\n          \"name\": \"thiserror-impl\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-impl-1.0.30/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/thiserror-impl-1.0.30/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"targets\": [\n              \"x86_64-unknown-linux-gnu\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"David Tolnay <dtolnay@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/dtolnay/thiserror\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.31\"\n    },\n    {\n      \"name\": \"tinyvec\",\n      \"version\": \"1.5.1\",\n      \"id\": \"tinyvec 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Zlib OR Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"`tinyvec` provides 100% safe vec-like data structures.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"arbitrary\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tinyvec_macros\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"smallvec\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"tinyvec\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec-1.5.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tinyvec\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec-1.5.1/tests/tinyvec.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\",\n            \"std\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"arrayvec\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec-1.5.1/tests/arrayvec.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec-1.5.1/benches/macros.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"smallvec\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec-1.5.1/benches/smallvec.rs\",\n          \"edition\": \"2018\",\n          \"required-features\": [\n            \"alloc\",\n            \"real_blackbox\"\n          ],\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"alloc\": [\n          \"tinyvec_macros\"\n        ],\n        \"arbitrary\": [\n          \"dep:arbitrary\"\n        ],\n        \"default\": [],\n        \"experimental_write_impl\": [],\n        \"grab_spare_slice\": [],\n        \"nightly_slice_partition_dedup\": [],\n        \"real_blackbox\": [\n          \"criterion/real_blackbox\"\n        ],\n        \"rustc_1_40\": [],\n        \"rustc_1_55\": [\n          \"rustc_1_40\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": [],\n        \"tinyvec_macros\": [\n          \"dep:tinyvec_macros\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec-1.5.1/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"alloc\",\n              \"std\",\n              \"grab_spare_slice\",\n              \"rustc_1_40\",\n              \"rustc_1_55\",\n              \"serde\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docs_rs\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"alloc\",\n            \"std\",\n            \"grab_spare_slice\",\n            \"rustc_1_40\",\n            \"rustc_1_55\",\n            \"serde\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Lokathor <zefria@gmail.com>\"\n      ],\n      \"categories\": [\n        \"data-structures\",\n        \"no-std\"\n      ],\n      \"keywords\": [\n        \"vec\",\n        \"no_std\",\n        \"no-std\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/Lokathor/tinyvec\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"tinyvec_macros\",\n      \"version\": \"0.1.0\",\n      \"id\": \"tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0 OR Zlib\",\n      \"license_file\": null,\n      \"description\": \"Some macros for tiny containers\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"tinyvec_macros\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec_macros-0.1.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tinyvec_macros-0.1.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Soveu <marx.tomasz@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/Soveu/tinyvec_macros\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"tokio\",\n      \"version\": \"1.17.0\",\n      \"id\": \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"An event-driven, non-blocking I/O platform for writing asynchronous I/O\\nbacked applications.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"bytes\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"memchr\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"mio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"num_cpus\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.8.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"once_cell\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.5.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"parking_lot\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.12.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pin-project-lite\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"socket2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"all\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-macros\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.7.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-stream\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"async-await\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"mockall\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.10.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tempfile\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^3.1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-stream\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"loom\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.5.2\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"futures\",\n            \"checkpoint\"\n          ],\n          \"target\": \"cfg(loom)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"proptest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(not(target_arch = \\\"wasm32\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"rand\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.8.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(not(target_arch = \\\"wasm32\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"socket2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(not(target_arch = \\\"wasm32\\\"))\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"mio-aio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"tokio\"\n          ],\n          \"target\": \"cfg(target_os = \\\"freebsd\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"tracing\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1.25\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"std\"\n          ],\n          \"target\": \"cfg(tokio_unstable)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.42\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"signal-hook-registry\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.1.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"libc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.42\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"nix\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.23\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(unix)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"winapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.8\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"ntapi\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.6\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(windows)\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"tokio\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_semaphore\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_semaphore.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_drop_recv\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_drop_recv.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_ctrl_c\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_ctrl_c.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"time_rt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/time_rt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read_to_string\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read_to_string.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_smoke\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/process_smoke.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"named_pipe\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/named_pipe.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_util_empty\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_util_empty.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_issue_2174\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/process_issue_2174.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test_clock\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/test_clock.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"task_local_set\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/task_local_set.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"join_handle_panic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/join_handle_panic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_copy_bidirectional\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_copy_bidirectional.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_into_split\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_into_split.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_raw_handle\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/process_raw_handle.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read_buf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read_buf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"task_blocking\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/task_blocking.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_into_std\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_into_std.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_split\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_split.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_async_fd\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_async_fd.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_echo\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_echo.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"async_send_sync\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/async_send_sync.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_socket\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_socket.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_usr1\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_usr1.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"task_builder\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/task_builder.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_broadcast\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_broadcast.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"time_pause\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/time_pause.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_semaphore_owned\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_semaphore_owned.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"time_interval\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/time_interval.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_twice\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_twice.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"buffered\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/buffered.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"net_bind_resource\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/net_bind_resource.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"time_timeout\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/time_timeout.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_copy\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_copy.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read_until\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read_until.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fs_file\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/fs_file.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"net_lookup_host\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/net_lookup_host.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read_to_end\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read_to_end.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_write_int\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_write_int.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"uds_cred\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/uds_cred.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_buf_reader\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_buf_reader.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_try_join\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/macros_try_join.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_poll_aio\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_poll_aio.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_pin\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/macros_pin.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_mpsc\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_mpsc.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_peek\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_peek.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_accept\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_accept.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_barrier\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_barrier.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"time_sleep\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/time_sleep.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_mem_stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_mem_stream.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_chain\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_chain.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rt_threaded\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/rt_threaded.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_fill_buf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_fill_buf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_errors\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_errors.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rt_common\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/rt_common.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"task_local\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/task_local.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_arg0\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/process_arg0.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_notify_both\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_notify_both.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_connect\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_connect.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_driver\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_driver.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fs_dir\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/fs_dir.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_no_rt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_no_rt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_join\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/macros_join.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_mutex\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_mutex.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_mutex_owned\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_mutex_owned.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_write_all_buf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_write_all_buf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_lines\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_lines.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_stream.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_split\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_split.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read_exact\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read_exact.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rt_basic\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/rt_basic.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_drop_rt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_drop_rt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/macros_test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_once_cell\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_once_cell.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"task_join_set\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/task_join_set.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"task_abort\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/task_abort.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"udp\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/udp.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_write_buf\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_write_buf.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rt_handle_block_on\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/rt_handle_block_on.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_drop_signal\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_drop_signal.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"macros_select\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/macros_select.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unwindsafe\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/unwindsafe.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_async_read\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_async_read.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"uds_stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/uds_stream.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"_require_full\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/_require_full.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_read_line\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_read_line.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_oneshot\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_oneshot.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_rwlock\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_rwlock.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_issue_42\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/process_issue_42.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_notify\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_notify.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"sync_watch\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/sync_watch.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tcp_shutdown\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/tcp_shutdown.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"uds_split\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/uds_split.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fs_link\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/fs_link.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"uds_datagram\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/uds_datagram.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fs_copy\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/fs_copy.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_take\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_take.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_buf_writer\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_buf_writer.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"rt_metrics\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/rt_metrics.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"signal_multi_rt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/signal_multi_rt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_driver_drop\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_driver_drop.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_write\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_write.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"io_write_all\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/io_write_all.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"no_rt\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/no_rt.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_kill_on_drop\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/process_kill_on_drop.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"fs\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/tests/fs.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"bytes\": [\n          \"dep:bytes\"\n        ],\n        \"default\": [],\n        \"fs\": [],\n        \"full\": [\n          \"fs\",\n          \"io-util\",\n          \"io-std\",\n          \"macros\",\n          \"net\",\n          \"parking_lot\",\n          \"process\",\n          \"rt\",\n          \"rt-multi-thread\",\n          \"signal\",\n          \"sync\",\n          \"time\"\n        ],\n        \"io-std\": [],\n        \"io-util\": [\n          \"memchr\",\n          \"bytes\"\n        ],\n        \"libc\": [\n          \"dep:libc\"\n        ],\n        \"macros\": [\n          \"tokio-macros\"\n        ],\n        \"memchr\": [\n          \"dep:memchr\"\n        ],\n        \"mio\": [\n          \"dep:mio\"\n        ],\n        \"net\": [\n          \"libc\",\n          \"mio/os-poll\",\n          \"mio/os-ext\",\n          \"mio/net\",\n          \"socket2\",\n          \"winapi/namedpipeapi\"\n        ],\n        \"num_cpus\": [\n          \"dep:num_cpus\"\n        ],\n        \"once_cell\": [\n          \"dep:once_cell\"\n        ],\n        \"parking_lot\": [\n          \"dep:parking_lot\"\n        ],\n        \"process\": [\n          \"bytes\",\n          \"once_cell\",\n          \"libc\",\n          \"mio/os-poll\",\n          \"mio/os-ext\",\n          \"mio/net\",\n          \"signal-hook-registry\",\n          \"winapi/threadpoollegacyapiset\"\n        ],\n        \"rt\": [],\n        \"rt-multi-thread\": [\n          \"num_cpus\",\n          \"rt\"\n        ],\n        \"signal\": [\n          \"once_cell\",\n          \"libc\",\n          \"mio/os-poll\",\n          \"mio/net\",\n          \"mio/os-ext\",\n          \"signal-hook-registry\",\n          \"winapi/consoleapi\"\n        ],\n        \"signal-hook-registry\": [\n          \"dep:signal-hook-registry\"\n        ],\n        \"socket2\": [\n          \"dep:socket2\"\n        ],\n        \"stats\": [],\n        \"sync\": [],\n        \"test-util\": [\n          \"rt\",\n          \"sync\",\n          \"time\"\n        ],\n        \"time\": [],\n        \"tokio-macros\": [\n          \"dep:tokio-macros\"\n        ],\n        \"tracing\": [\n          \"dep:tracing\"\n        ],\n        \"winapi\": [\n          \"dep:winapi\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.17.0/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustc-args\": [\n              \"--cfg\",\n              \"tokio_unstable\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\",\n              \"--cfg\",\n              \"tokio_unstable\"\n            ]\n          }\n        },\n        \"playground\": {\n          \"features\": [\n            \"full\",\n            \"test-util\"\n          ]\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Tokio Contributors <team@tokio.rs>\"\n      ],\n      \"categories\": [\n        \"asynchronous\",\n        \"network-programming\"\n      ],\n      \"keywords\": [\n        \"io\",\n        \"async\",\n        \"non-blocking\",\n        \"futures\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/tokio-rs/tokio\",\n      \"homepage\": \"https://tokio.rs\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": \"1.49\"\n    },\n    {\n      \"name\": \"tokio-rustls\",\n      \"version\": \"0.22.0\",\n      \"id\": \"tokio-rustls 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Asynchronous TLS/SSL streams for Tokio using Rustls.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"rustls\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"webpki\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures-util\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"full\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"webpki-roots\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"tokio-rustls\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-rustls-0.22.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"early-data\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-rustls-0.22.0/tests/early-data.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"badssl\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-rustls-0.22.0/tests/badssl.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-rustls-0.22.0/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"dangerous_configuration\": [\n          \"rustls/dangerous_configuration\"\n        ],\n        \"early-data\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-rustls-0.22.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"quininer kel <quininer@live.com>\"\n      ],\n      \"categories\": [\n        \"asynchronous\",\n        \"cryptography\",\n        \"network-programming\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/tokio-rs/tls\",\n      \"homepage\": \"https://github.com/tokio-rs/tls\",\n      \"documentation\": \"https://docs.rs/tokio-rustls\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"tokio-stream\",\n      \"version\": \"0.1.8\",\n      \"id\": \"tokio-stream 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT\",\n      \"license_file\": null,\n      \"description\": \"Utilities to work with `Stream` and `tokio`.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"futures-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"pin-project-lite\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.8.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"sync\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio-util\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.6.3\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"async-stream\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"proptest\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tokio\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.2.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"full\",\n            \"test-util\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"tokio-stream\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"time_throttle\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/time_throttle.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_iter\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_iter.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_once\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_once.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"async_send_sync\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/async_send_sync.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_collect\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_collect.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_timeout\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_timeout.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_stream_map\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_stream_map.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_pending\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_pending.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_fuse\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_fuse.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_merge\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_merge.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"watch\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/watch.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_empty\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_empty.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"stream_chain\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/tests/stream_chain.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"time\"\n        ],\n        \"fs\": [\n          \"tokio/fs\"\n        ],\n        \"io-util\": [\n          \"tokio/io-util\"\n        ],\n        \"net\": [\n          \"tokio/net\"\n        ],\n        \"signal\": [\n          \"tokio/signal\"\n        ],\n        \"sync\": [\n          \"tokio/sync\",\n          \"tokio-util\"\n        ],\n        \"time\": [\n          \"tokio/time\"\n        ],\n        \"tokio-util\": [\n          \"dep:tokio-util\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/tokio-stream-0.1.8/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ],\n            \"rustdoc-args\": [\n              \"--cfg\",\n              \"docsrs\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Tokio Contributors <team@tokio.rs>\"\n      ],\n      \"categories\": [\n        \"asynchronous\"\n      ],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/tokio-rs/tokio\",\n      \"homepage\": \"https://tokio.rs\",\n      \"documentation\": \"https://docs.rs/tokio-stream/0.1.8/tokio_stream\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"typenum\",\n      \"version\": \"1.15.0\",\n      \"id\": \"typenum 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Typenum is a Rust library for type-level numbers evaluated at\\n    compile time. It currently supports bits, unsigned integers, and signed\\n    integers. It also provides a type-level array of type-level numbers, but its\\n    implementation is incomplete.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"scale-info\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"typenum\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/typenum-1.15.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"test\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/typenum-1.15.0/tests/test.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-main\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/typenum-1.15.0/build/main.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"force_unix_path_separator\": [],\n        \"i128\": [],\n        \"no_std\": [],\n        \"scale-info\": [\n          \"dep:scale-info\"\n        ],\n        \"scale_info\": [\n          \"scale-info/derive\"\n        ],\n        \"strict\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/typenum-1.15.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Paho Lurie-Gregg <paho@paholg.com>\",\n        \"Andre Bogus <bogusandre@gmail.com>\"\n      ],\n      \"categories\": [\n        \"no-std\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/paholg/typenum\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/typenum\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"unicode-bidi\",\n      \"version\": \"0.3.7\",\n      \"id\": \"unicode-bidi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT / Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Implementation of the Unicode Bidirectional Algorithm\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"flame\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"flamer\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \">=0.8, <2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \">=0.8, <2.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"unicode_bidi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-bidi-0.3.7/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"bench_it\": [],\n        \"default\": [\n          \"std\"\n        ],\n        \"flame\": [\n          \"dep:flame\"\n        ],\n        \"flame_it\": [\n          \"flame\",\n          \"flamer\"\n        ],\n        \"flamer\": [\n          \"dep:flamer\"\n        ],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"std\": [],\n        \"unstable\": [],\n        \"with_serde\": [\n          \"serde\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-bidi-0.3.7/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The Servo Project Developers\"\n      ],\n      \"categories\": [\n        \"no-std\",\n        \"encoding\",\n        \"text-processing\"\n      ],\n      \"keywords\": [\n        \"rtl\",\n        \"unicode\",\n        \"text\",\n        \"layout\",\n        \"bidi\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/servo/unicode-bidi\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/unicode-bidi/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"unicode-normalization\",\n      \"version\": \"0.1.19\",\n      \"id\": \"unicode-normalization 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"This crate provides functions for normalization of\\nUnicode strings, including Canonical and Compatible\\nDecomposition and Recomposition, as described in\\nUnicode Standard Annex #15.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"tinyvec\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"alloc\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"unicode-normalization\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-normalization-0.1.19/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"bench\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-normalization-0.1.19/benches/bench.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-normalization-0.1.19/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"kwantam <kwantam@gmail.com>\",\n        \"Manish Goregaokar <manishsmail@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"text\",\n        \"unicode\",\n        \"normalization\",\n        \"decomposition\",\n        \"recomposition\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/unicode-rs/unicode-normalization\",\n      \"homepage\": \"https://github.com/unicode-rs/unicode-normalization\",\n      \"documentation\": \"https://docs.rs/unicode-normalization/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"unicode-segmentation\",\n      \"version\": \"1.9.0\",\n      \"id\": \"unicode-segmentation 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"This crate provides Grapheme Cluster, Word and Sentence boundaries\\naccording to Unicode Standard Annex #29 rules.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quickcheck\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"unicode-segmentation\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-segmentation-1.9.0/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"graphemes\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-segmentation-1.9.0/benches/graphemes.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unicode_words\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-segmentation-1.9.0/benches/unicode_words.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"word_bounds\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-segmentation-1.9.0/benches/word_bounds.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"no_std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-segmentation-1.9.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"kwantam <kwantam@gmail.com>\",\n        \"Manish Goregaokar <manishsmail@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"text\",\n        \"unicode\",\n        \"grapheme\",\n        \"word\",\n        \"boundary\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/unicode-rs/unicode-segmentation\",\n      \"homepage\": \"https://github.com/unicode-rs/unicode-segmentation\",\n      \"documentation\": \"https://unicode-rs.github.io/unicode-segmentation\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"unicode-xid\",\n      \"version\": \"0.2.2\",\n      \"id\": \"unicode-xid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Determine whether characters have the XID_Start\\nor XID_Continue properties according to\\nUnicode Standard Annex #31.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"criterion\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"unicode-xid\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-xid-0.2.2/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"exhaustive_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-xid-0.2.2/tests/exhaustive_tests.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"xid\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-xid-0.2.2/benches/xid.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"bench\": [],\n        \"default\": [],\n        \"no_std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode-xid-0.2.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"erick.tryzelaar <erick.tryzelaar@gmail.com>\",\n        \"kwantam <kwantam@gmail.com>\",\n        \"Manish Goregaokar <manishsmail@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"text\",\n        \"unicode\",\n        \"xid\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/unicode-rs/unicode-xid\",\n      \"homepage\": \"https://github.com/unicode-rs/unicode-xid\",\n      \"documentation\": \"https://unicode-rs.github.io/unicode-xid\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"unicode_categories\",\n      \"version\": \"0.1.1\",\n      \"id\": \"unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT OR Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Query Unicode category membership for chars\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"unicode_categories\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode_categories-0.1.1/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/unicode_categories-0.1.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Sean Gillespie <sean@swgillespie.me>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"unicode\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/swgillespie/unicode-categories\",\n      \"homepage\": null,\n      \"documentation\": \"http://swgillespie.github.io/unicode-categories/unicode_categories/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"untrusted\",\n      \"version\": \"0.7.1\",\n      \"id\": \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"ISC\",\n      \"license_file\": null,\n      \"description\": \"Safe, fast, zero-panic, zero-crashing, zero-allocation parsing of untrusted inputs in Rust.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"untrusted\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/untrusted-0.7.1/src/untrusted.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/untrusted-0.7.1/tests/tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/untrusted-0.7.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Brian Smith <brian@briansmith.org>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/briansmith/untrusted\",\n      \"homepage\": null,\n      \"documentation\": \"https://briansmith.org/rustdoc/untrusted/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"url\",\n      \"version\": \"2.2.2\",\n      \"id\": \"url 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"URL library for Rust, based on the WHATWG URL Standard\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"form_urlencoded\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"idna\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"matches\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"percent-encoding\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^2.1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"derive\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"bencher\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"url\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/url-2.2.2/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"data\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/url-2.2.2/tests/data.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unit\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/url-2.2.2/tests/unit.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bench\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"parse_url\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/url-2.2.2/benches/parse_url.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"serde\": [\n          \"dep:serde\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/url-2.2.2/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The rust-url developers\"\n      ],\n      \"categories\": [\n        \"parser-implementations\",\n        \"web-programming\",\n        \"encoding\"\n      ],\n      \"keywords\": [\n        \"url\",\n        \"parser\"\n      ],\n      \"readme\": \"../README.md\",\n      \"repository\": \"https://github.com/servo/rust-url\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/url\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"vcpkg\",\n      \"version\": \"0.2.15\",\n      \"id\": \"vcpkg 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"A library to find native dependencies in a vcpkg tree at build\\ntime in order to be used in Cargo build scripts.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"tempdir\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.7\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"vcpkg\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/vcpkg-0.2.15/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/vcpkg-0.2.15/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Jim McGrath <jimmc2@gmail.com>\"\n      ],\n      \"categories\": [\n        \"development-tools::build-utils\"\n      ],\n      \"keywords\": [\n        \"build-dependencies\",\n        \"windows\",\n        \"macos\",\n        \"linux\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/mcgoo/vcpkg-rs\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/vcpkg\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"version_check\",\n      \"version\": \"0.9.4\",\n      \"id\": \"version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Tiny crate to check the version of the installed/running rustc.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"version_check\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/version_check-0.9.4/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/version_check-0.9.4/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Sergio Benitez <sb@sergio.bz>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"version\",\n        \"rustc\",\n        \"minimum\",\n        \"check\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/SergioBenitez/version_check\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/version_check/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasi\",\n      \"version\": \"0.10.2+wasi-snapshot-preview1\",\n      \"id\": \"wasi 0.10.2+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"Experimental WASI API bindings for Rust\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-alloc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"wasi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasi-0.10.2+wasi-snapshot-preview1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"default\": [\n          \"std\"\n        ],\n        \"rustc-dep-of-std\": [\n          \"compiler_builtins\",\n          \"core\",\n          \"rustc-std-workspace-alloc\"\n        ],\n        \"rustc-std-workspace-alloc\": [\n          \"dep:rustc-std-workspace-alloc\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasi-0.10.2+wasi-snapshot-preview1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The Cranelift Project Developers\"\n      ],\n      \"categories\": [\n        \"no-std\",\n        \"wasm\"\n      ],\n      \"keywords\": [\n        \"webassembly\",\n        \"wasm\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/bytecodealliance/wasi\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/wasi\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasi\",\n      \"version\": \"0.11.0+wasi-snapshot-preview1\",\n      \"id\": \"wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\n      \"license_file\": null,\n      \"description\": \"Experimental WASI API bindings for Rust\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"compiler_builtins\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-core\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": \"core\",\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"rustc-std-workspace-alloc\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"wasi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasi-0.11.0+wasi-snapshot-preview1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"compiler_builtins\": [\n          \"dep:compiler_builtins\"\n        ],\n        \"core\": [\n          \"dep:core\"\n        ],\n        \"default\": [\n          \"std\"\n        ],\n        \"rustc-dep-of-std\": [\n          \"compiler_builtins\",\n          \"core\",\n          \"rustc-std-workspace-alloc\"\n        ],\n        \"rustc-std-workspace-alloc\": [\n          \"dep:rustc-std-workspace-alloc\"\n        ],\n        \"std\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasi-0.11.0+wasi-snapshot-preview1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The Cranelift Project Developers\"\n      ],\n      \"categories\": [\n        \"no-std\",\n        \"wasm\"\n      ],\n      \"keywords\": [\n        \"webassembly\",\n        \"wasm\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/bytecodealliance/wasi\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/wasi\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasm-bindgen\",\n      \"version\": \"0.2.80\",\n      \"id\": \"wasm-bindgen 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Easy support for interacting between JS and Rust.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"cfg-if\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_json\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": true,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-macro\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"js-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.57\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"serde_derive\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.4.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.3.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test-crate-a\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test-crate-b\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"wasm-bindgen\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"wasm\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/tests/wasm/main.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"must_use\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/tests/must_use.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"unwrap_throw\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/tests/unwrap_throw.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"std-crate-no-std-dep\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/tests/std-crate-no-std-dep.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"headless\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/tests/headless/main.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"non_wasm\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/tests/non_wasm.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"spans\",\n          \"std\"\n        ],\n        \"enable-interning\": [\n          \"std\"\n        ],\n        \"nightly\": [],\n        \"serde\": [\n          \"dep:serde\"\n        ],\n        \"serde-serialize\": [\n          \"serde\",\n          \"serde_json\",\n          \"std\"\n        ],\n        \"serde_json\": [\n          \"dep:serde_json\"\n        ],\n        \"spans\": [\n          \"wasm-bindgen-macro/spans\"\n        ],\n        \"std\": [],\n        \"strict-macro\": [\n          \"wasm-bindgen-macro/strict-macro\"\n        ],\n        \"xxx_debug_only_print_generated_code\": [\n          \"wasm-bindgen-macro/xxx_debug_only_print_generated_code\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-0.2.80/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"features\": [\n              \"serde-serialize\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [\n        \"wasm\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen\",\n      \"homepage\": \"https://rustwasm.github.io/\",\n      \"documentation\": \"https://docs.rs/wasm-bindgen\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasm-bindgen-backend\",\n      \"version\": \"0.2.80\",\n      \"id\": \"wasm-bindgen-backend 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Backend code generation of the wasm-bindgen tool\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"bumpalo\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^3.0.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"lazy_static\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.2\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"log\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"full\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-shared\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"wasm-bindgen-backend\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-backend-0.2.80/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"extra-traits\": [\n          \"syn/extra-traits\"\n        ],\n        \"spans\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-backend-0.2.80/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen/tree/master/crates/backend\",\n      \"homepage\": \"https://rustwasm.github.io/wasm-bindgen/\",\n      \"documentation\": \"https://docs.rs/wasm-bindgen-backend\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasm-bindgen-macro\",\n      \"version\": \"0.2.80\",\n      \"id\": \"wasm-bindgen-macro 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Definition of the `#[wasm_bindgen]` attribute, an internal dependency\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-macro-support\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"trybuild\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.80\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"strict-macro\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"proc-macro\"\n          ],\n          \"crate_types\": [\n            \"proc-macro\"\n          ],\n          \"name\": \"wasm-bindgen-macro\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-macro-0.2.80/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"ui\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-macro-0.2.80/tests/ui.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"spans\": [\n          \"wasm-bindgen-macro-support/spans\"\n        ],\n        \"strict-macro\": [\n          \"wasm-bindgen-macro-support/strict-macro\"\n        ],\n        \"xxx_debug_only_print_generated_code\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-macro-0.2.80/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro\",\n      \"homepage\": \"https://rustwasm.github.io/wasm-bindgen/\",\n      \"documentation\": \"https://docs.rs/wasm-bindgen\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasm-bindgen-macro-support\",\n      \"version\": \"0.2.80\",\n      \"id\": \"wasm-bindgen-macro-support 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"The part of the implementation of the `#[wasm_bindgen]` attribute that is not in the shared backend crate\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"proc-macro2\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"quote\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"syn\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^1.0.67\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [\n            \"visit\",\n            \"full\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-backend\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-shared\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"=0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"wasm-bindgen-macro-support\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-macro-support-0.2.80/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"extra-traits\": [\n          \"syn/extra-traits\"\n        ],\n        \"spans\": [\n          \"wasm-bindgen-backend/spans\"\n        ],\n        \"strict-macro\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-macro-support-0.2.80/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen/tree/master/crates/macro-support\",\n      \"homepage\": \"https://rustwasm.github.io/wasm-bindgen/\",\n      \"documentation\": \"https://docs.rs/wasm-bindgen\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"wasm-bindgen-shared\",\n      \"version\": \"0.2.80\",\n      \"id\": \"wasm-bindgen-shared 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Shared support between wasm-bindgen and wasm-bindgen cli, an internal\\ndependency.\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"wasm-bindgen-shared\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-shared-0.2.80/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-shared-0.2.80/build.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-shared-0.2.80/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": null,\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen/tree/master/crates/shared\",\n      \"homepage\": \"https://rustwasm.github.io/wasm-bindgen/\",\n      \"documentation\": \"https://docs.rs/wasm-bindgen-shared\",\n      \"edition\": \"2018\",\n      \"links\": \"wasm_bindgen\",\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"web-sys\",\n      \"version\": \"0.3.57\",\n      \"id\": \"web-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Bindings for all Web APIs, a procedurally generated crate from WebIDL\\n\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"js-sys\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.57\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.2.80\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-futures\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"wasm-bindgen-test\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.3.30\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"cfg(target_arch = \\\"wasm32\\\")\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"web-sys\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/web-sys-0.3.57/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": false\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"wasm\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/web-sys-0.3.57/tests/wasm/main.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"AbortController\": [],\n        \"AbortSignal\": [\n          \"EventTarget\"\n        ],\n        \"AddEventListenerOptions\": [],\n        \"AesCbcParams\": [],\n        \"AesCtrParams\": [],\n        \"AesDerivedKeyParams\": [],\n        \"AesGcmParams\": [],\n        \"AesKeyAlgorithm\": [],\n        \"AesKeyGenParams\": [],\n        \"Algorithm\": [],\n        \"AlignSetting\": [],\n        \"AllowedBluetoothDevice\": [],\n        \"AllowedUsbDevice\": [],\n        \"AlphaOption\": [],\n        \"AnalyserNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"AnalyserOptions\": [],\n        \"AngleInstancedArrays\": [],\n        \"Animation\": [\n          \"EventTarget\"\n        ],\n        \"AnimationEffect\": [],\n        \"AnimationEvent\": [\n          \"Event\"\n        ],\n        \"AnimationEventInit\": [],\n        \"AnimationPlayState\": [],\n        \"AnimationPlaybackEvent\": [\n          \"Event\"\n        ],\n        \"AnimationPlaybackEventInit\": [],\n        \"AnimationPropertyDetails\": [],\n        \"AnimationPropertyValueDetails\": [],\n        \"AnimationTimeline\": [],\n        \"AssignedNodesOptions\": [],\n        \"AttestationConveyancePreference\": [],\n        \"Attr\": [\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"AttributeNameValue\": [],\n        \"AudioBuffer\": [],\n        \"AudioBufferOptions\": [],\n        \"AudioBufferSourceNode\": [\n          \"AudioNode\",\n          \"AudioScheduledSourceNode\",\n          \"EventTarget\"\n        ],\n        \"AudioBufferSourceOptions\": [],\n        \"AudioConfiguration\": [],\n        \"AudioContext\": [\n          \"BaseAudioContext\",\n          \"EventTarget\"\n        ],\n        \"AudioContextOptions\": [],\n        \"AudioContextState\": [],\n        \"AudioData\": [],\n        \"AudioDataCopyToOptions\": [],\n        \"AudioDataInit\": [],\n        \"AudioDecoder\": [],\n        \"AudioDecoderConfig\": [],\n        \"AudioDecoderInit\": [],\n        \"AudioDecoderSupport\": [],\n        \"AudioDestinationNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"AudioEncoder\": [],\n        \"AudioEncoderConfig\": [],\n        \"AudioEncoderInit\": [],\n        \"AudioEncoderSupport\": [],\n        \"AudioListener\": [],\n        \"AudioNode\": [\n          \"EventTarget\"\n        ],\n        \"AudioNodeOptions\": [],\n        \"AudioParam\": [],\n        \"AudioParamMap\": [],\n        \"AudioProcessingEvent\": [\n          \"Event\"\n        ],\n        \"AudioSampleFormat\": [],\n        \"AudioScheduledSourceNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"AudioStreamTrack\": [\n          \"EventTarget\",\n          \"MediaStreamTrack\"\n        ],\n        \"AudioTrack\": [],\n        \"AudioTrackList\": [\n          \"EventTarget\"\n        ],\n        \"AudioWorklet\": [\n          \"Worklet\"\n        ],\n        \"AudioWorkletGlobalScope\": [\n          \"WorkletGlobalScope\"\n        ],\n        \"AudioWorkletNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"AudioWorkletNodeOptions\": [],\n        \"AudioWorkletProcessor\": [],\n        \"AuthenticationExtensionsClientInputs\": [],\n        \"AuthenticationExtensionsClientOutputs\": [],\n        \"AuthenticatorAssertionResponse\": [\n          \"AuthenticatorResponse\"\n        ],\n        \"AuthenticatorAttachment\": [],\n        \"AuthenticatorAttestationResponse\": [\n          \"AuthenticatorResponse\"\n        ],\n        \"AuthenticatorResponse\": [],\n        \"AuthenticatorSelectionCriteria\": [],\n        \"AuthenticatorTransport\": [],\n        \"AutoKeyword\": [],\n        \"AutocompleteInfo\": [],\n        \"BarProp\": [],\n        \"BaseAudioContext\": [\n          \"EventTarget\"\n        ],\n        \"BaseComputedKeyframe\": [],\n        \"BaseKeyframe\": [],\n        \"BasePropertyIndexedKeyframe\": [],\n        \"BasicCardRequest\": [],\n        \"BasicCardResponse\": [],\n        \"BasicCardType\": [],\n        \"BatteryManager\": [\n          \"EventTarget\"\n        ],\n        \"BeforeUnloadEvent\": [\n          \"Event\"\n        ],\n        \"BinaryType\": [],\n        \"BiquadFilterNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"BiquadFilterOptions\": [],\n        \"BiquadFilterType\": [],\n        \"Blob\": [],\n        \"BlobEvent\": [\n          \"Event\"\n        ],\n        \"BlobEventInit\": [],\n        \"BlobPropertyBag\": [],\n        \"BlockParsingOptions\": [],\n        \"Bluetooth\": [\n          \"EventTarget\"\n        ],\n        \"BluetoothAdvertisingEvent\": [\n          \"Event\"\n        ],\n        \"BluetoothAdvertisingEventInit\": [],\n        \"BluetoothCharacteristicProperties\": [],\n        \"BluetoothDataFilterInit\": [],\n        \"BluetoothDevice\": [\n          \"EventTarget\"\n        ],\n        \"BluetoothLeScanFilterInit\": [],\n        \"BluetoothManufacturerDataMap\": [],\n        \"BluetoothPermissionDescriptor\": [],\n        \"BluetoothPermissionResult\": [\n          \"EventTarget\",\n          \"PermissionStatus\"\n        ],\n        \"BluetoothPermissionStorage\": [],\n        \"BluetoothRemoteGattCharacteristic\": [\n          \"EventTarget\"\n        ],\n        \"BluetoothRemoteGattDescriptor\": [],\n        \"BluetoothRemoteGattServer\": [],\n        \"BluetoothRemoteGattService\": [\n          \"EventTarget\"\n        ],\n        \"BluetoothServiceDataMap\": [],\n        \"BluetoothUuid\": [],\n        \"BoxQuadOptions\": [],\n        \"BroadcastChannel\": [\n          \"EventTarget\"\n        ],\n        \"BrowserElementDownloadOptions\": [],\n        \"BrowserElementExecuteScriptOptions\": [],\n        \"BrowserFeedWriter\": [],\n        \"BrowserFindCaseSensitivity\": [],\n        \"BrowserFindDirection\": [],\n        \"Cache\": [],\n        \"CacheBatchOperation\": [],\n        \"CacheQueryOptions\": [],\n        \"CacheStorage\": [],\n        \"CacheStorageNamespace\": [],\n        \"CanvasCaptureMediaStream\": [\n          \"EventTarget\",\n          \"MediaStream\"\n        ],\n        \"CanvasGradient\": [],\n        \"CanvasPattern\": [],\n        \"CanvasRenderingContext2d\": [],\n        \"CanvasWindingRule\": [],\n        \"CaretChangedReason\": [],\n        \"CaretPosition\": [],\n        \"CaretStateChangedEventInit\": [],\n        \"CdataSection\": [\n          \"CharacterData\",\n          \"EventTarget\",\n          \"Node\",\n          \"Text\"\n        ],\n        \"ChannelCountMode\": [],\n        \"ChannelInterpretation\": [],\n        \"ChannelMergerNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"ChannelMergerOptions\": [],\n        \"ChannelPixelLayout\": [],\n        \"ChannelPixelLayoutDataType\": [],\n        \"ChannelSplitterNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"ChannelSplitterOptions\": [],\n        \"CharacterData\": [\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"CheckerboardReason\": [],\n        \"CheckerboardReport\": [],\n        \"CheckerboardReportService\": [],\n        \"ChromeFilePropertyBag\": [],\n        \"ChromeWorker\": [\n          \"EventTarget\",\n          \"Worker\"\n        ],\n        \"Client\": [],\n        \"ClientQueryOptions\": [],\n        \"ClientRectsAndTexts\": [],\n        \"ClientType\": [],\n        \"Clients\": [],\n        \"Clipboard\": [\n          \"EventTarget\"\n        ],\n        \"ClipboardEvent\": [\n          \"Event\"\n        ],\n        \"ClipboardEventInit\": [],\n        \"ClipboardItem\": [],\n        \"ClipboardItemOptions\": [],\n        \"ClipboardPermissionDescriptor\": [],\n        \"CloseEvent\": [\n          \"Event\"\n        ],\n        \"CloseEventInit\": [],\n        \"CodecState\": [],\n        \"CollectedClientData\": [],\n        \"Comment\": [\n          \"CharacterData\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"CompositeOperation\": [],\n        \"CompositionEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"CompositionEventInit\": [],\n        \"ComputedEffectTiming\": [],\n        \"ConnStatusDict\": [],\n        \"ConnectionType\": [],\n        \"ConsoleCounter\": [],\n        \"ConsoleCounterError\": [],\n        \"ConsoleEvent\": [],\n        \"ConsoleInstance\": [],\n        \"ConsoleInstanceOptions\": [],\n        \"ConsoleLevel\": [],\n        \"ConsoleLogLevel\": [],\n        \"ConsoleProfileEvent\": [],\n        \"ConsoleStackEntry\": [],\n        \"ConsoleTimerError\": [],\n        \"ConsoleTimerLogOrEnd\": [],\n        \"ConsoleTimerStart\": [],\n        \"ConstantSourceNode\": [\n          \"AudioNode\",\n          \"AudioScheduledSourceNode\",\n          \"EventTarget\"\n        ],\n        \"ConstantSourceOptions\": [],\n        \"ConstrainBooleanParameters\": [],\n        \"ConstrainDomStringParameters\": [],\n        \"ConstrainDoubleRange\": [],\n        \"ConstrainLongRange\": [],\n        \"ContextAttributes2d\": [],\n        \"ConvertCoordinateOptions\": [],\n        \"ConvolverNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"ConvolverOptions\": [],\n        \"Coordinates\": [],\n        \"Credential\": [],\n        \"CredentialCreationOptions\": [],\n        \"CredentialRequestOptions\": [],\n        \"CredentialsContainer\": [],\n        \"Crypto\": [],\n        \"CryptoKey\": [],\n        \"CryptoKeyPair\": [],\n        \"Csp\": [],\n        \"CspPolicies\": [],\n        \"CspReport\": [],\n        \"CspReportProperties\": [],\n        \"CssAnimation\": [\n          \"Animation\",\n          \"EventTarget\"\n        ],\n        \"CssBoxType\": [],\n        \"CssConditionRule\": [\n          \"CssGroupingRule\",\n          \"CssRule\"\n        ],\n        \"CssCounterStyleRule\": [\n          \"CssRule\"\n        ],\n        \"CssFontFaceRule\": [\n          \"CssRule\"\n        ],\n        \"CssFontFeatureValuesRule\": [\n          \"CssRule\"\n        ],\n        \"CssGroupingRule\": [\n          \"CssRule\"\n        ],\n        \"CssImportRule\": [\n          \"CssRule\"\n        ],\n        \"CssKeyframeRule\": [\n          \"CssRule\"\n        ],\n        \"CssKeyframesRule\": [\n          \"CssRule\"\n        ],\n        \"CssMediaRule\": [\n          \"CssConditionRule\",\n          \"CssGroupingRule\",\n          \"CssRule\"\n        ],\n        \"CssNamespaceRule\": [\n          \"CssRule\"\n        ],\n        \"CssPageRule\": [\n          \"CssRule\"\n        ],\n        \"CssPseudoElement\": [],\n        \"CssRule\": [],\n        \"CssRuleList\": [],\n        \"CssStyleDeclaration\": [],\n        \"CssStyleRule\": [\n          \"CssRule\"\n        ],\n        \"CssStyleSheet\": [\n          \"StyleSheet\"\n        ],\n        \"CssStyleSheetParsingMode\": [],\n        \"CssSupportsRule\": [\n          \"CssConditionRule\",\n          \"CssGroupingRule\",\n          \"CssRule\"\n        ],\n        \"CssTransition\": [\n          \"Animation\",\n          \"EventTarget\"\n        ],\n        \"CustomElementRegistry\": [],\n        \"CustomEvent\": [\n          \"Event\"\n        ],\n        \"CustomEventInit\": [],\n        \"DataTransfer\": [],\n        \"DataTransferItem\": [],\n        \"DataTransferItemList\": [],\n        \"DateTimeValue\": [],\n        \"DecoderDoctorNotification\": [],\n        \"DecoderDoctorNotificationType\": [],\n        \"DedicatedWorkerGlobalScope\": [\n          \"EventTarget\",\n          \"WorkerGlobalScope\"\n        ],\n        \"DelayNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"DelayOptions\": [],\n        \"DeviceAcceleration\": [],\n        \"DeviceAccelerationInit\": [],\n        \"DeviceLightEvent\": [\n          \"Event\"\n        ],\n        \"DeviceLightEventInit\": [],\n        \"DeviceMotionEvent\": [\n          \"Event\"\n        ],\n        \"DeviceMotionEventInit\": [],\n        \"DeviceOrientationEvent\": [\n          \"Event\"\n        ],\n        \"DeviceOrientationEventInit\": [],\n        \"DeviceProximityEvent\": [\n          \"Event\"\n        ],\n        \"DeviceProximityEventInit\": [],\n        \"DeviceRotationRate\": [],\n        \"DeviceRotationRateInit\": [],\n        \"DhKeyDeriveParams\": [],\n        \"DirectionSetting\": [],\n        \"Directory\": [],\n        \"DisplayMediaStreamConstraints\": [],\n        \"DisplayNameOptions\": [],\n        \"DisplayNameResult\": [],\n        \"DistanceModelType\": [],\n        \"DnsCacheDict\": [],\n        \"DnsCacheEntry\": [],\n        \"DnsLookupDict\": [],\n        \"Document\": [\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"DocumentFragment\": [\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"DocumentTimeline\": [\n          \"AnimationTimeline\"\n        ],\n        \"DocumentTimelineOptions\": [],\n        \"DocumentType\": [\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"DomError\": [],\n        \"DomException\": [],\n        \"DomImplementation\": [],\n        \"DomMatrix\": [\n          \"DomMatrixReadOnly\"\n        ],\n        \"DomMatrixReadOnly\": [],\n        \"DomParser\": [],\n        \"DomPoint\": [\n          \"DomPointReadOnly\"\n        ],\n        \"DomPointInit\": [],\n        \"DomPointReadOnly\": [],\n        \"DomQuad\": [],\n        \"DomQuadInit\": [],\n        \"DomQuadJson\": [],\n        \"DomRect\": [\n          \"DomRectReadOnly\"\n        ],\n        \"DomRectInit\": [],\n        \"DomRectList\": [],\n        \"DomRectReadOnly\": [],\n        \"DomRequest\": [\n          \"EventTarget\"\n        ],\n        \"DomRequestReadyState\": [],\n        \"DomStringList\": [],\n        \"DomStringMap\": [],\n        \"DomTokenList\": [],\n        \"DomWindowResizeEventDetail\": [],\n        \"DragEvent\": [\n          \"Event\",\n          \"MouseEvent\",\n          \"UiEvent\"\n        ],\n        \"DragEventInit\": [],\n        \"DynamicsCompressorNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"DynamicsCompressorOptions\": [],\n        \"EcKeyAlgorithm\": [],\n        \"EcKeyGenParams\": [],\n        \"EcKeyImportParams\": [],\n        \"EcdhKeyDeriveParams\": [],\n        \"EcdsaParams\": [],\n        \"EffectTiming\": [],\n        \"Element\": [\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"ElementCreationOptions\": [],\n        \"ElementDefinitionOptions\": [],\n        \"EncodedAudioChunk\": [],\n        \"EncodedAudioChunkInit\": [],\n        \"EncodedAudioChunkMetadata\": [],\n        \"EncodedAudioChunkType\": [],\n        \"EncodedVideoChunk\": [],\n        \"EncodedVideoChunkInit\": [],\n        \"EncodedVideoChunkMetadata\": [],\n        \"EncodedVideoChunkType\": [],\n        \"EndingTypes\": [],\n        \"ErrorCallback\": [],\n        \"ErrorEvent\": [\n          \"Event\"\n        ],\n        \"ErrorEventInit\": [],\n        \"Event\": [],\n        \"EventInit\": [],\n        \"EventListener\": [],\n        \"EventListenerOptions\": [],\n        \"EventModifierInit\": [],\n        \"EventSource\": [\n          \"EventTarget\"\n        ],\n        \"EventSourceInit\": [],\n        \"EventTarget\": [],\n        \"Exception\": [],\n        \"ExtBlendMinmax\": [],\n        \"ExtColorBufferFloat\": [],\n        \"ExtColorBufferHalfFloat\": [],\n        \"ExtDisjointTimerQuery\": [],\n        \"ExtFragDepth\": [],\n        \"ExtSRgb\": [],\n        \"ExtShaderTextureLod\": [],\n        \"ExtTextureFilterAnisotropic\": [],\n        \"ExtendableEvent\": [\n          \"Event\"\n        ],\n        \"ExtendableEventInit\": [],\n        \"ExtendableMessageEvent\": [\n          \"Event\",\n          \"ExtendableEvent\"\n        ],\n        \"ExtendableMessageEventInit\": [],\n        \"External\": [],\n        \"FakePluginMimeEntry\": [],\n        \"FakePluginTagInit\": [],\n        \"FetchEvent\": [\n          \"Event\",\n          \"ExtendableEvent\"\n        ],\n        \"FetchEventInit\": [],\n        \"FetchObserver\": [\n          \"EventTarget\"\n        ],\n        \"FetchReadableStreamReadDataArray\": [],\n        \"FetchReadableStreamReadDataDone\": [],\n        \"FetchState\": [],\n        \"File\": [\n          \"Blob\"\n        ],\n        \"FileCallback\": [],\n        \"FileList\": [],\n        \"FilePropertyBag\": [],\n        \"FileReader\": [\n          \"EventTarget\"\n        ],\n        \"FileReaderSync\": [],\n        \"FileSystem\": [],\n        \"FileSystemDirectoryEntry\": [\n          \"FileSystemEntry\"\n        ],\n        \"FileSystemDirectoryReader\": [],\n        \"FileSystemEntriesCallback\": [],\n        \"FileSystemEntry\": [],\n        \"FileSystemEntryCallback\": [],\n        \"FileSystemFileEntry\": [\n          \"FileSystemEntry\"\n        ],\n        \"FileSystemFlags\": [],\n        \"FillMode\": [],\n        \"FlashClassification\": [],\n        \"FlexLineGrowthState\": [],\n        \"FocusEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"FocusEventInit\": [],\n        \"FontFace\": [],\n        \"FontFaceDescriptors\": [],\n        \"FontFaceLoadStatus\": [],\n        \"FontFaceSet\": [\n          \"EventTarget\"\n        ],\n        \"FontFaceSetIterator\": [],\n        \"FontFaceSetIteratorResult\": [],\n        \"FontFaceSetLoadEvent\": [\n          \"Event\"\n        ],\n        \"FontFaceSetLoadEventInit\": [],\n        \"FontFaceSetLoadStatus\": [],\n        \"FormData\": [],\n        \"FrameType\": [],\n        \"FuzzingFunctions\": [],\n        \"GainNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"GainOptions\": [],\n        \"Gamepad\": [],\n        \"GamepadAxisMoveEvent\": [\n          \"Event\",\n          \"GamepadEvent\"\n        ],\n        \"GamepadAxisMoveEventInit\": [],\n        \"GamepadButton\": [],\n        \"GamepadButtonEvent\": [\n          \"Event\",\n          \"GamepadEvent\"\n        ],\n        \"GamepadButtonEventInit\": [],\n        \"GamepadEvent\": [\n          \"Event\"\n        ],\n        \"GamepadEventInit\": [],\n        \"GamepadHand\": [],\n        \"GamepadHapticActuator\": [],\n        \"GamepadHapticActuatorType\": [],\n        \"GamepadMappingType\": [],\n        \"GamepadPose\": [],\n        \"GamepadServiceTest\": [],\n        \"Geolocation\": [],\n        \"GetNotificationOptions\": [],\n        \"GetRootNodeOptions\": [],\n        \"GetUserMediaRequest\": [],\n        \"Gpu\": [],\n        \"GpuAdapter\": [],\n        \"GpuAddressMode\": [],\n        \"GpuBindGroup\": [],\n        \"GpuBindGroupDescriptor\": [],\n        \"GpuBindGroupEntry\": [],\n        \"GpuBindGroupLayout\": [],\n        \"GpuBindGroupLayoutDescriptor\": [],\n        \"GpuBindGroupLayoutEntry\": [],\n        \"GpuBlendComponent\": [],\n        \"GpuBlendFactor\": [],\n        \"GpuBlendOperation\": [],\n        \"GpuBlendState\": [],\n        \"GpuBuffer\": [],\n        \"GpuBufferBinding\": [],\n        \"GpuBufferBindingLayout\": [],\n        \"GpuBufferBindingType\": [],\n        \"GpuBufferDescriptor\": [],\n        \"GpuBufferUsage\": [],\n        \"GpuCanvasCompositingAlphaMode\": [],\n        \"GpuCanvasConfiguration\": [],\n        \"GpuCanvasContext\": [],\n        \"GpuColorDict\": [],\n        \"GpuColorTargetState\": [],\n        \"GpuColorWrite\": [],\n        \"GpuCommandBuffer\": [],\n        \"GpuCommandBufferDescriptor\": [],\n        \"GpuCommandEncoder\": [],\n        \"GpuCommandEncoderDescriptor\": [],\n        \"GpuCompareFunction\": [],\n        \"GpuCompilationInfo\": [],\n        \"GpuCompilationMessage\": [],\n        \"GpuCompilationMessageType\": [],\n        \"GpuComputePassDescriptor\": [],\n        \"GpuComputePassEncoder\": [],\n        \"GpuComputePipeline\": [],\n        \"GpuComputePipelineDescriptor\": [],\n        \"GpuCullMode\": [],\n        \"GpuDepthStencilState\": [],\n        \"GpuDevice\": [\n          \"EventTarget\"\n        ],\n        \"GpuDeviceDescriptor\": [],\n        \"GpuDeviceLostInfo\": [],\n        \"GpuDeviceLostReason\": [],\n        \"GpuErrorFilter\": [],\n        \"GpuExtent3dDict\": [],\n        \"GpuExternalTexture\": [],\n        \"GpuExternalTextureBindingLayout\": [],\n        \"GpuExternalTextureDescriptor\": [],\n        \"GpuFeatureName\": [],\n        \"GpuFilterMode\": [],\n        \"GpuFragmentState\": [],\n        \"GpuFrontFace\": [],\n        \"GpuImageCopyBuffer\": [],\n        \"GpuImageCopyExternalImage\": [],\n        \"GpuImageCopyTexture\": [],\n        \"GpuImageCopyTextureTagged\": [],\n        \"GpuImageDataLayout\": [],\n        \"GpuIndexFormat\": [],\n        \"GpuLoadOp\": [],\n        \"GpuMapMode\": [],\n        \"GpuMultisampleState\": [],\n        \"GpuObjectDescriptorBase\": [],\n        \"GpuOrigin2dDict\": [],\n        \"GpuOrigin3dDict\": [],\n        \"GpuOutOfMemoryError\": [],\n        \"GpuPipelineDescriptorBase\": [],\n        \"GpuPipelineLayout\": [],\n        \"GpuPipelineLayoutDescriptor\": [],\n        \"GpuPipelineStatisticName\": [],\n        \"GpuPowerPreference\": [],\n        \"GpuPredefinedColorSpace\": [],\n        \"GpuPrimitiveState\": [],\n        \"GpuPrimitiveTopology\": [],\n        \"GpuProgrammableStage\": [],\n        \"GpuQuerySet\": [],\n        \"GpuQuerySetDescriptor\": [],\n        \"GpuQueryType\": [],\n        \"GpuQueue\": [],\n        \"GpuRenderBundle\": [],\n        \"GpuRenderBundleDescriptor\": [],\n        \"GpuRenderBundleEncoder\": [],\n        \"GpuRenderBundleEncoderDescriptor\": [],\n        \"GpuRenderPassColorAttachment\": [],\n        \"GpuRenderPassDepthStencilAttachment\": [],\n        \"GpuRenderPassDescriptor\": [],\n        \"GpuRenderPassEncoder\": [],\n        \"GpuRenderPassLayout\": [],\n        \"GpuRenderPipeline\": [],\n        \"GpuRenderPipelineDescriptor\": [],\n        \"GpuRequestAdapterOptions\": [],\n        \"GpuSampler\": [],\n        \"GpuSamplerBindingLayout\": [],\n        \"GpuSamplerBindingType\": [],\n        \"GpuSamplerDescriptor\": [],\n        \"GpuShaderModule\": [],\n        \"GpuShaderModuleDescriptor\": [],\n        \"GpuShaderStage\": [],\n        \"GpuStencilFaceState\": [],\n        \"GpuStencilOperation\": [],\n        \"GpuStorageTextureAccess\": [],\n        \"GpuStorageTextureBindingLayout\": [],\n        \"GpuStoreOp\": [],\n        \"GpuSupportedFeatures\": [],\n        \"GpuSupportedLimits\": [],\n        \"GpuTexture\": [],\n        \"GpuTextureAspect\": [],\n        \"GpuTextureBindingLayout\": [],\n        \"GpuTextureDescriptor\": [],\n        \"GpuTextureDimension\": [],\n        \"GpuTextureFormat\": [],\n        \"GpuTextureSampleType\": [],\n        \"GpuTextureUsage\": [],\n        \"GpuTextureView\": [],\n        \"GpuTextureViewDescriptor\": [],\n        \"GpuTextureViewDimension\": [],\n        \"GpuUncapturedErrorEvent\": [\n          \"Event\"\n        ],\n        \"GpuUncapturedErrorEventInit\": [],\n        \"GpuValidationError\": [],\n        \"GpuVertexAttribute\": [],\n        \"GpuVertexBufferLayout\": [],\n        \"GpuVertexFormat\": [],\n        \"GpuVertexState\": [],\n        \"GpuVertexStepMode\": [],\n        \"GridDeclaration\": [],\n        \"GridTrackState\": [],\n        \"GroupedHistoryEventInit\": [],\n        \"HalfOpenInfoDict\": [],\n        \"HardwareAcceleration\": [],\n        \"HashChangeEvent\": [\n          \"Event\"\n        ],\n        \"HashChangeEventInit\": [],\n        \"Headers\": [],\n        \"HeadersGuardEnum\": [],\n        \"Hid\": [\n          \"EventTarget\"\n        ],\n        \"HidCollectionInfo\": [],\n        \"HidConnectionEvent\": [\n          \"Event\"\n        ],\n        \"HidConnectionEventInit\": [],\n        \"HidDevice\": [\n          \"EventTarget\"\n        ],\n        \"HidDeviceFilter\": [],\n        \"HidDeviceRequestOptions\": [],\n        \"HidInputReportEvent\": [\n          \"Event\"\n        ],\n        \"HidInputReportEventInit\": [],\n        \"HidReportInfo\": [],\n        \"HidReportItem\": [],\n        \"HidUnitSystem\": [],\n        \"HiddenPluginEventInit\": [],\n        \"History\": [],\n        \"HitRegionOptions\": [],\n        \"HkdfParams\": [],\n        \"HmacDerivedKeyParams\": [],\n        \"HmacImportParams\": [],\n        \"HmacKeyAlgorithm\": [],\n        \"HmacKeyGenParams\": [],\n        \"HtmlAllCollection\": [],\n        \"HtmlAnchorElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlAreaElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlAudioElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"HtmlMediaElement\",\n          \"Node\"\n        ],\n        \"HtmlBaseElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlBodyElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlBrElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlButtonElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlCanvasElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlCollection\": [],\n        \"HtmlDListElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDataElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDataListElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDetailsElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDialogElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDirectoryElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDivElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlDocument\": [\n          \"Document\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"HtmlElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"HtmlEmbedElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlFieldSetElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlFontElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlFormControlsCollection\": [\n          \"HtmlCollection\"\n        ],\n        \"HtmlFormElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlFrameElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlFrameSetElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlHeadElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlHeadingElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlHrElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlHtmlElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlIFrameElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlImageElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlInputElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlLabelElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlLegendElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlLiElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlLinkElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlMapElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlMediaElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlMenuElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlMenuItemElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlMetaElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlMeterElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlModElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlOListElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlObjectElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlOptGroupElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlOptionElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlOptionsCollection\": [\n          \"HtmlCollection\"\n        ],\n        \"HtmlOutputElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlParagraphElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlParamElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlPictureElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlPreElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlProgressElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlQuoteElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlScriptElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlSelectElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlSlotElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlSourceElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlSpanElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlStyleElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTableCaptionElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTableCellElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTableColElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTableElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTableRowElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTableSectionElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTemplateElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTextAreaElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTimeElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTitleElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlTrackElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlUListElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlUnknownElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"Node\"\n        ],\n        \"HtmlVideoElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"HtmlElement\",\n          \"HtmlMediaElement\",\n          \"Node\"\n        ],\n        \"HttpConnDict\": [],\n        \"HttpConnInfo\": [],\n        \"HttpConnectionElement\": [],\n        \"IdbCursor\": [],\n        \"IdbCursorDirection\": [],\n        \"IdbCursorWithValue\": [\n          \"IdbCursor\"\n        ],\n        \"IdbDatabase\": [\n          \"EventTarget\"\n        ],\n        \"IdbFactory\": [],\n        \"IdbFileHandle\": [\n          \"EventTarget\"\n        ],\n        \"IdbFileMetadataParameters\": [],\n        \"IdbFileRequest\": [\n          \"DomRequest\",\n          \"EventTarget\"\n        ],\n        \"IdbIndex\": [],\n        \"IdbIndexParameters\": [],\n        \"IdbKeyRange\": [],\n        \"IdbLocaleAwareKeyRange\": [\n          \"IdbKeyRange\"\n        ],\n        \"IdbMutableFile\": [\n          \"EventTarget\"\n        ],\n        \"IdbObjectStore\": [],\n        \"IdbObjectStoreParameters\": [],\n        \"IdbOpenDbOptions\": [],\n        \"IdbOpenDbRequest\": [\n          \"EventTarget\",\n          \"IdbRequest\"\n        ],\n        \"IdbRequest\": [\n          \"EventTarget\"\n        ],\n        \"IdbRequestReadyState\": [],\n        \"IdbTransaction\": [\n          \"EventTarget\"\n        ],\n        \"IdbTransactionMode\": [],\n        \"IdbVersionChangeEvent\": [\n          \"Event\"\n        ],\n        \"IdbVersionChangeEventInit\": [],\n        \"IdleDeadline\": [],\n        \"IdleRequestOptions\": [],\n        \"IirFilterNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"IirFilterOptions\": [],\n        \"ImageBitmap\": [],\n        \"ImageBitmapFormat\": [],\n        \"ImageBitmapRenderingContext\": [],\n        \"ImageCapture\": [],\n        \"ImageCaptureError\": [],\n        \"ImageCaptureErrorEvent\": [\n          \"Event\"\n        ],\n        \"ImageCaptureErrorEventInit\": [],\n        \"ImageData\": [],\n        \"ImageDecodeOptions\": [],\n        \"ImageDecodeResult\": [],\n        \"ImageDecoder\": [],\n        \"ImageDecoderInit\": [],\n        \"ImageTrack\": [\n          \"EventTarget\"\n        ],\n        \"ImageTrackList\": [],\n        \"InputEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"InputEventInit\": [],\n        \"InstallTriggerData\": [],\n        \"IntersectionObserver\": [],\n        \"IntersectionObserverEntry\": [],\n        \"IntersectionObserverEntryInit\": [],\n        \"IntersectionObserverInit\": [],\n        \"IntlUtils\": [],\n        \"IterableKeyAndValueResult\": [],\n        \"IterableKeyOrValueResult\": [],\n        \"IterationCompositeOperation\": [],\n        \"JsonWebKey\": [],\n        \"KeyAlgorithm\": [],\n        \"KeyEvent\": [],\n        \"KeyIdsInitData\": [],\n        \"KeyboardEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"KeyboardEventInit\": [],\n        \"KeyframeEffect\": [\n          \"AnimationEffect\"\n        ],\n        \"KeyframeEffectOptions\": [],\n        \"L10nElement\": [],\n        \"L10nValue\": [],\n        \"LatencyMode\": [],\n        \"LifecycleCallbacks\": [],\n        \"LineAlignSetting\": [],\n        \"ListBoxObject\": [],\n        \"LocalMediaStream\": [\n          \"EventTarget\",\n          \"MediaStream\"\n        ],\n        \"LocaleInfo\": [],\n        \"Location\": [],\n        \"MediaCapabilities\": [],\n        \"MediaCapabilitiesInfo\": [],\n        \"MediaConfiguration\": [],\n        \"MediaDecodingConfiguration\": [],\n        \"MediaDecodingType\": [],\n        \"MediaDeviceInfo\": [],\n        \"MediaDeviceKind\": [],\n        \"MediaDevices\": [\n          \"EventTarget\"\n        ],\n        \"MediaElementAudioSourceNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"MediaElementAudioSourceOptions\": [],\n        \"MediaEncodingConfiguration\": [],\n        \"MediaEncodingType\": [],\n        \"MediaEncryptedEvent\": [\n          \"Event\"\n        ],\n        \"MediaError\": [],\n        \"MediaKeyError\": [\n          \"Event\"\n        ],\n        \"MediaKeyMessageEvent\": [\n          \"Event\"\n        ],\n        \"MediaKeyMessageEventInit\": [],\n        \"MediaKeyMessageType\": [],\n        \"MediaKeyNeededEventInit\": [],\n        \"MediaKeySession\": [\n          \"EventTarget\"\n        ],\n        \"MediaKeySessionType\": [],\n        \"MediaKeyStatus\": [],\n        \"MediaKeyStatusMap\": [],\n        \"MediaKeySystemAccess\": [],\n        \"MediaKeySystemConfiguration\": [],\n        \"MediaKeySystemMediaCapability\": [],\n        \"MediaKeySystemStatus\": [],\n        \"MediaKeys\": [],\n        \"MediaKeysPolicy\": [],\n        \"MediaKeysRequirement\": [],\n        \"MediaList\": [],\n        \"MediaQueryList\": [\n          \"EventTarget\"\n        ],\n        \"MediaQueryListEvent\": [\n          \"Event\"\n        ],\n        \"MediaQueryListEventInit\": [],\n        \"MediaRecorder\": [\n          \"EventTarget\"\n        ],\n        \"MediaRecorderErrorEvent\": [\n          \"Event\"\n        ],\n        \"MediaRecorderErrorEventInit\": [],\n        \"MediaRecorderOptions\": [],\n        \"MediaSource\": [\n          \"EventTarget\"\n        ],\n        \"MediaSourceEndOfStreamError\": [],\n        \"MediaSourceEnum\": [],\n        \"MediaSourceReadyState\": [],\n        \"MediaStream\": [\n          \"EventTarget\"\n        ],\n        \"MediaStreamAudioDestinationNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"MediaStreamAudioSourceNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"MediaStreamAudioSourceOptions\": [],\n        \"MediaStreamConstraints\": [],\n        \"MediaStreamError\": [],\n        \"MediaStreamEvent\": [\n          \"Event\"\n        ],\n        \"MediaStreamEventInit\": [],\n        \"MediaStreamTrack\": [\n          \"EventTarget\"\n        ],\n        \"MediaStreamTrackEvent\": [\n          \"Event\"\n        ],\n        \"MediaStreamTrackEventInit\": [],\n        \"MediaStreamTrackState\": [],\n        \"MediaTrackConstraintSet\": [],\n        \"MediaTrackConstraints\": [],\n        \"MediaTrackSettings\": [],\n        \"MediaTrackSupportedConstraints\": [],\n        \"MessageChannel\": [],\n        \"MessageEvent\": [\n          \"Event\"\n        ],\n        \"MessageEventInit\": [],\n        \"MessagePort\": [\n          \"EventTarget\"\n        ],\n        \"MidiAccess\": [\n          \"EventTarget\"\n        ],\n        \"MidiConnectionEvent\": [\n          \"Event\"\n        ],\n        \"MidiConnectionEventInit\": [],\n        \"MidiInput\": [\n          \"EventTarget\",\n          \"MidiPort\"\n        ],\n        \"MidiInputMap\": [],\n        \"MidiMessageEvent\": [\n          \"Event\"\n        ],\n        \"MidiMessageEventInit\": [],\n        \"MidiOptions\": [],\n        \"MidiOutput\": [\n          \"EventTarget\",\n          \"MidiPort\"\n        ],\n        \"MidiOutputMap\": [],\n        \"MidiPort\": [\n          \"EventTarget\"\n        ],\n        \"MidiPortConnectionState\": [],\n        \"MidiPortDeviceState\": [],\n        \"MidiPortType\": [],\n        \"MimeType\": [],\n        \"MimeTypeArray\": [],\n        \"MouseEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"MouseEventInit\": [],\n        \"MouseScrollEvent\": [\n          \"Event\",\n          \"MouseEvent\",\n          \"UiEvent\"\n        ],\n        \"MozDebug\": [],\n        \"MutationEvent\": [\n          \"Event\"\n        ],\n        \"MutationObserver\": [],\n        \"MutationObserverInit\": [],\n        \"MutationObservingInfo\": [],\n        \"MutationRecord\": [],\n        \"NamedNodeMap\": [],\n        \"NativeOsFileReadOptions\": [],\n        \"NativeOsFileWriteAtomicOptions\": [],\n        \"NavigationType\": [],\n        \"Navigator\": [],\n        \"NavigatorAutomationInformation\": [],\n        \"NetworkCommandOptions\": [],\n        \"NetworkInformation\": [\n          \"EventTarget\"\n        ],\n        \"NetworkResultOptions\": [],\n        \"Node\": [\n          \"EventTarget\"\n        ],\n        \"NodeFilter\": [],\n        \"NodeIterator\": [],\n        \"NodeList\": [],\n        \"Notification\": [\n          \"EventTarget\"\n        ],\n        \"NotificationBehavior\": [],\n        \"NotificationDirection\": [],\n        \"NotificationEvent\": [\n          \"Event\",\n          \"ExtendableEvent\"\n        ],\n        \"NotificationEventInit\": [],\n        \"NotificationOptions\": [],\n        \"NotificationPermission\": [],\n        \"ObserverCallback\": [],\n        \"OesElementIndexUint\": [],\n        \"OesStandardDerivatives\": [],\n        \"OesTextureFloat\": [],\n        \"OesTextureFloatLinear\": [],\n        \"OesTextureHalfFloat\": [],\n        \"OesTextureHalfFloatLinear\": [],\n        \"OesVertexArrayObject\": [],\n        \"OfflineAudioCompletionEvent\": [\n          \"Event\"\n        ],\n        \"OfflineAudioCompletionEventInit\": [],\n        \"OfflineAudioContext\": [\n          \"BaseAudioContext\",\n          \"EventTarget\"\n        ],\n        \"OfflineAudioContextOptions\": [],\n        \"OfflineResourceList\": [\n          \"EventTarget\"\n        ],\n        \"OffscreenCanvas\": [\n          \"EventTarget\"\n        ],\n        \"OpenWindowEventDetail\": [],\n        \"OptionalEffectTiming\": [],\n        \"OrientationLockType\": [],\n        \"OrientationType\": [],\n        \"OscillatorNode\": [\n          \"AudioNode\",\n          \"AudioScheduledSourceNode\",\n          \"EventTarget\"\n        ],\n        \"OscillatorOptions\": [],\n        \"OscillatorType\": [],\n        \"OverSampleType\": [],\n        \"PageTransitionEvent\": [\n          \"Event\"\n        ],\n        \"PageTransitionEventInit\": [],\n        \"PaintRequest\": [],\n        \"PaintRequestList\": [],\n        \"PaintWorkletGlobalScope\": [\n          \"WorkletGlobalScope\"\n        ],\n        \"PannerNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"PannerOptions\": [],\n        \"PanningModelType\": [],\n        \"Path2d\": [],\n        \"PaymentAddress\": [],\n        \"PaymentComplete\": [],\n        \"PaymentMethodChangeEvent\": [\n          \"Event\",\n          \"PaymentRequestUpdateEvent\"\n        ],\n        \"PaymentMethodChangeEventInit\": [],\n        \"PaymentRequestUpdateEvent\": [\n          \"Event\"\n        ],\n        \"PaymentRequestUpdateEventInit\": [],\n        \"PaymentResponse\": [],\n        \"Pbkdf2Params\": [],\n        \"PcImplIceConnectionState\": [],\n        \"PcImplIceGatheringState\": [],\n        \"PcImplSignalingState\": [],\n        \"PcObserverStateType\": [],\n        \"Performance\": [\n          \"EventTarget\"\n        ],\n        \"PerformanceEntry\": [],\n        \"PerformanceEntryEventInit\": [],\n        \"PerformanceEntryFilterOptions\": [],\n        \"PerformanceMark\": [\n          \"PerformanceEntry\"\n        ],\n        \"PerformanceMeasure\": [\n          \"PerformanceEntry\"\n        ],\n        \"PerformanceNavigation\": [],\n        \"PerformanceNavigationTiming\": [\n          \"PerformanceEntry\",\n          \"PerformanceResourceTiming\"\n        ],\n        \"PerformanceObserver\": [],\n        \"PerformanceObserverEntryList\": [],\n        \"PerformanceObserverInit\": [],\n        \"PerformanceResourceTiming\": [\n          \"PerformanceEntry\"\n        ],\n        \"PerformanceServerTiming\": [],\n        \"PerformanceTiming\": [],\n        \"PeriodicWave\": [],\n        \"PeriodicWaveConstraints\": [],\n        \"PeriodicWaveOptions\": [],\n        \"PermissionDescriptor\": [],\n        \"PermissionName\": [],\n        \"PermissionState\": [],\n        \"PermissionStatus\": [\n          \"EventTarget\"\n        ],\n        \"Permissions\": [],\n        \"PlaneLayout\": [],\n        \"PlaybackDirection\": [],\n        \"Plugin\": [],\n        \"PluginArray\": [],\n        \"PluginCrashedEventInit\": [],\n        \"PointerEvent\": [\n          \"Event\",\n          \"MouseEvent\",\n          \"UiEvent\"\n        ],\n        \"PointerEventInit\": [],\n        \"PopStateEvent\": [\n          \"Event\"\n        ],\n        \"PopStateEventInit\": [],\n        \"PopupBlockedEvent\": [\n          \"Event\"\n        ],\n        \"PopupBlockedEventInit\": [],\n        \"Position\": [],\n        \"PositionAlignSetting\": [],\n        \"PositionError\": [],\n        \"PositionOptions\": [],\n        \"Presentation\": [],\n        \"PresentationAvailability\": [\n          \"EventTarget\"\n        ],\n        \"PresentationConnection\": [\n          \"EventTarget\"\n        ],\n        \"PresentationConnectionAvailableEvent\": [\n          \"Event\"\n        ],\n        \"PresentationConnectionAvailableEventInit\": [],\n        \"PresentationConnectionBinaryType\": [],\n        \"PresentationConnectionCloseEvent\": [\n          \"Event\"\n        ],\n        \"PresentationConnectionCloseEventInit\": [],\n        \"PresentationConnectionClosedReason\": [],\n        \"PresentationConnectionList\": [\n          \"EventTarget\"\n        ],\n        \"PresentationConnectionState\": [],\n        \"PresentationReceiver\": [],\n        \"PresentationRequest\": [\n          \"EventTarget\"\n        ],\n        \"PresentationStyle\": [],\n        \"ProcessingInstruction\": [\n          \"CharacterData\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"ProfileTimelineLayerRect\": [],\n        \"ProfileTimelineMarker\": [],\n        \"ProfileTimelineMessagePortOperationType\": [],\n        \"ProfileTimelineStackFrame\": [],\n        \"ProfileTimelineWorkerOperationType\": [],\n        \"ProgressEvent\": [\n          \"Event\"\n        ],\n        \"ProgressEventInit\": [],\n        \"PromiseNativeHandler\": [],\n        \"PromiseRejectionEvent\": [\n          \"Event\"\n        ],\n        \"PromiseRejectionEventInit\": [],\n        \"PublicKeyCredential\": [\n          \"Credential\"\n        ],\n        \"PublicKeyCredentialCreationOptions\": [],\n        \"PublicKeyCredentialDescriptor\": [],\n        \"PublicKeyCredentialEntity\": [],\n        \"PublicKeyCredentialParameters\": [],\n        \"PublicKeyCredentialRequestOptions\": [],\n        \"PublicKeyCredentialRpEntity\": [],\n        \"PublicKeyCredentialType\": [],\n        \"PublicKeyCredentialUserEntity\": [],\n        \"PushEncryptionKeyName\": [],\n        \"PushEvent\": [\n          \"Event\",\n          \"ExtendableEvent\"\n        ],\n        \"PushEventInit\": [],\n        \"PushManager\": [],\n        \"PushMessageData\": [],\n        \"PushPermissionState\": [],\n        \"PushSubscription\": [],\n        \"PushSubscriptionInit\": [],\n        \"PushSubscriptionJson\": [],\n        \"PushSubscriptionKeys\": [],\n        \"PushSubscriptionOptions\": [],\n        \"PushSubscriptionOptionsInit\": [],\n        \"QueuingStrategy\": [],\n        \"RadioNodeList\": [\n          \"NodeList\"\n        ],\n        \"Range\": [],\n        \"RcwnPerfStats\": [],\n        \"RcwnStatus\": [],\n        \"ReadableStream\": [],\n        \"ReadableStreamByobReadResult\": [],\n        \"ReadableStreamByobReader\": [],\n        \"ReadableStreamDefaultReadResult\": [],\n        \"ReadableStreamDefaultReader\": [],\n        \"ReadableStreamGetReaderOptions\": [],\n        \"ReadableStreamIteratorOptions\": [],\n        \"ReadableStreamReaderMode\": [],\n        \"ReadableWritablePair\": [],\n        \"RecordingState\": [],\n        \"ReferrerPolicy\": [],\n        \"RegisterRequest\": [],\n        \"RegisterResponse\": [],\n        \"RegisteredKey\": [],\n        \"RegistrationOptions\": [],\n        \"Request\": [],\n        \"RequestCache\": [],\n        \"RequestCredentials\": [],\n        \"RequestDestination\": [],\n        \"RequestDeviceOptions\": [],\n        \"RequestInit\": [],\n        \"RequestMediaKeySystemAccessNotification\": [],\n        \"RequestMode\": [],\n        \"RequestRedirect\": [],\n        \"ResizeObserver\": [],\n        \"ResizeObserverBoxOptions\": [],\n        \"ResizeObserverEntry\": [],\n        \"ResizeObserverOptions\": [],\n        \"ResizeObserverSize\": [],\n        \"Response\": [],\n        \"ResponseInit\": [],\n        \"ResponseType\": [],\n        \"RsaHashedImportParams\": [],\n        \"RsaOaepParams\": [],\n        \"RsaOtherPrimesInfo\": [],\n        \"RsaPssParams\": [],\n        \"RtcAnswerOptions\": [],\n        \"RtcBundlePolicy\": [],\n        \"RtcCertificate\": [],\n        \"RtcCertificateExpiration\": [],\n        \"RtcCodecStats\": [],\n        \"RtcConfiguration\": [],\n        \"RtcDataChannel\": [\n          \"EventTarget\"\n        ],\n        \"RtcDataChannelEvent\": [\n          \"Event\"\n        ],\n        \"RtcDataChannelEventInit\": [],\n        \"RtcDataChannelInit\": [],\n        \"RtcDataChannelState\": [],\n        \"RtcDataChannelType\": [],\n        \"RtcDegradationPreference\": [],\n        \"RtcFecParameters\": [],\n        \"RtcIceCandidate\": [],\n        \"RtcIceCandidateInit\": [],\n        \"RtcIceCandidatePairStats\": [],\n        \"RtcIceCandidateStats\": [],\n        \"RtcIceComponentStats\": [],\n        \"RtcIceConnectionState\": [],\n        \"RtcIceCredentialType\": [],\n        \"RtcIceGatheringState\": [],\n        \"RtcIceServer\": [],\n        \"RtcIceTransportPolicy\": [],\n        \"RtcIdentityAssertion\": [],\n        \"RtcIdentityAssertionResult\": [],\n        \"RtcIdentityProvider\": [],\n        \"RtcIdentityProviderDetails\": [],\n        \"RtcIdentityProviderOptions\": [],\n        \"RtcIdentityProviderRegistrar\": [],\n        \"RtcIdentityValidationResult\": [],\n        \"RtcInboundRtpStreamStats\": [],\n        \"RtcLifecycleEvent\": [],\n        \"RtcMediaStreamStats\": [],\n        \"RtcMediaStreamTrackStats\": [],\n        \"RtcOfferAnswerOptions\": [],\n        \"RtcOfferOptions\": [],\n        \"RtcOutboundRtpStreamStats\": [],\n        \"RtcPeerConnection\": [\n          \"EventTarget\"\n        ],\n        \"RtcPeerConnectionIceEvent\": [\n          \"Event\"\n        ],\n        \"RtcPeerConnectionIceEventInit\": [],\n        \"RtcPriorityType\": [],\n        \"RtcRtcpParameters\": [],\n        \"RtcRtpCodecParameters\": [],\n        \"RtcRtpContributingSource\": [],\n        \"RtcRtpEncodingParameters\": [],\n        \"RtcRtpHeaderExtensionParameters\": [],\n        \"RtcRtpParameters\": [],\n        \"RtcRtpReceiver\": [],\n        \"RtcRtpSender\": [],\n        \"RtcRtpSourceEntry\": [],\n        \"RtcRtpSourceEntryType\": [],\n        \"RtcRtpSynchronizationSource\": [],\n        \"RtcRtpTransceiver\": [],\n        \"RtcRtpTransceiverDirection\": [],\n        \"RtcRtpTransceiverInit\": [],\n        \"RtcRtxParameters\": [],\n        \"RtcSdpType\": [],\n        \"RtcSessionDescription\": [],\n        \"RtcSessionDescriptionInit\": [],\n        \"RtcSignalingState\": [],\n        \"RtcStats\": [],\n        \"RtcStatsIceCandidatePairState\": [],\n        \"RtcStatsIceCandidateType\": [],\n        \"RtcStatsReport\": [],\n        \"RtcStatsReportInternal\": [],\n        \"RtcStatsType\": [],\n        \"RtcTrackEvent\": [\n          \"Event\"\n        ],\n        \"RtcTrackEventInit\": [],\n        \"RtcTransportStats\": [],\n        \"RtcdtmfSender\": [\n          \"EventTarget\"\n        ],\n        \"RtcdtmfToneChangeEvent\": [\n          \"Event\"\n        ],\n        \"RtcdtmfToneChangeEventInit\": [],\n        \"RtcrtpContributingSourceStats\": [],\n        \"RtcrtpStreamStats\": [],\n        \"Screen\": [\n          \"EventTarget\"\n        ],\n        \"ScreenColorGamut\": [],\n        \"ScreenLuminance\": [],\n        \"ScreenOrientation\": [\n          \"EventTarget\"\n        ],\n        \"ScriptProcessorNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"ScrollAreaEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"ScrollBehavior\": [],\n        \"ScrollBoxObject\": [],\n        \"ScrollIntoViewOptions\": [],\n        \"ScrollLogicalPosition\": [],\n        \"ScrollOptions\": [],\n        \"ScrollRestoration\": [],\n        \"ScrollSetting\": [],\n        \"ScrollState\": [],\n        \"ScrollToOptions\": [],\n        \"ScrollViewChangeEventInit\": [],\n        \"SecurityPolicyViolationEvent\": [\n          \"Event\"\n        ],\n        \"SecurityPolicyViolationEventDisposition\": [],\n        \"SecurityPolicyViolationEventInit\": [],\n        \"Selection\": [],\n        \"ServerSocketOptions\": [],\n        \"ServiceWorker\": [\n          \"EventTarget\"\n        ],\n        \"ServiceWorkerContainer\": [\n          \"EventTarget\"\n        ],\n        \"ServiceWorkerGlobalScope\": [\n          \"EventTarget\",\n          \"WorkerGlobalScope\"\n        ],\n        \"ServiceWorkerRegistration\": [\n          \"EventTarget\"\n        ],\n        \"ServiceWorkerState\": [],\n        \"ServiceWorkerUpdateViaCache\": [],\n        \"ShadowRoot\": [\n          \"DocumentFragment\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"ShadowRootInit\": [],\n        \"ShadowRootMode\": [],\n        \"ShareData\": [],\n        \"SharedWorker\": [\n          \"EventTarget\"\n        ],\n        \"SharedWorkerGlobalScope\": [\n          \"EventTarget\",\n          \"WorkerGlobalScope\"\n        ],\n        \"SignResponse\": [],\n        \"SocketElement\": [],\n        \"SocketOptions\": [],\n        \"SocketReadyState\": [],\n        \"SocketsDict\": [],\n        \"SourceBuffer\": [\n          \"EventTarget\"\n        ],\n        \"SourceBufferAppendMode\": [],\n        \"SourceBufferList\": [\n          \"EventTarget\"\n        ],\n        \"SpeechGrammar\": [],\n        \"SpeechGrammarList\": [],\n        \"SpeechRecognition\": [\n          \"EventTarget\"\n        ],\n        \"SpeechRecognitionAlternative\": [],\n        \"SpeechRecognitionError\": [\n          \"Event\"\n        ],\n        \"SpeechRecognitionErrorCode\": [],\n        \"SpeechRecognitionErrorInit\": [],\n        \"SpeechRecognitionEvent\": [\n          \"Event\"\n        ],\n        \"SpeechRecognitionEventInit\": [],\n        \"SpeechRecognitionResult\": [],\n        \"SpeechRecognitionResultList\": [],\n        \"SpeechSynthesis\": [\n          \"EventTarget\"\n        ],\n        \"SpeechSynthesisErrorCode\": [],\n        \"SpeechSynthesisErrorEvent\": [\n          \"Event\",\n          \"SpeechSynthesisEvent\"\n        ],\n        \"SpeechSynthesisErrorEventInit\": [],\n        \"SpeechSynthesisEvent\": [\n          \"Event\"\n        ],\n        \"SpeechSynthesisEventInit\": [],\n        \"SpeechSynthesisUtterance\": [\n          \"EventTarget\"\n        ],\n        \"SpeechSynthesisVoice\": [],\n        \"StereoPannerNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"StereoPannerOptions\": [],\n        \"Storage\": [],\n        \"StorageEstimate\": [],\n        \"StorageEvent\": [\n          \"Event\"\n        ],\n        \"StorageEventInit\": [],\n        \"StorageManager\": [],\n        \"StorageType\": [],\n        \"StreamPipeOptions\": [],\n        \"StyleRuleChangeEventInit\": [],\n        \"StyleSheet\": [],\n        \"StyleSheetApplicableStateChangeEventInit\": [],\n        \"StyleSheetChangeEventInit\": [],\n        \"StyleSheetList\": [],\n        \"SubtleCrypto\": [],\n        \"SupportedType\": [],\n        \"SvcOutputMetadata\": [],\n        \"SvgAngle\": [],\n        \"SvgAnimateElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgAnimationElement\",\n          \"SvgElement\"\n        ],\n        \"SvgAnimateMotionElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgAnimationElement\",\n          \"SvgElement\"\n        ],\n        \"SvgAnimateTransformElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgAnimationElement\",\n          \"SvgElement\"\n        ],\n        \"SvgAnimatedAngle\": [],\n        \"SvgAnimatedBoolean\": [],\n        \"SvgAnimatedEnumeration\": [],\n        \"SvgAnimatedInteger\": [],\n        \"SvgAnimatedLength\": [],\n        \"SvgAnimatedLengthList\": [],\n        \"SvgAnimatedNumber\": [],\n        \"SvgAnimatedNumberList\": [],\n        \"SvgAnimatedPreserveAspectRatio\": [],\n        \"SvgAnimatedRect\": [],\n        \"SvgAnimatedString\": [],\n        \"SvgAnimatedTransformList\": [],\n        \"SvgAnimationElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgBoundingBoxOptions\": [],\n        \"SvgCircleElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgClipPathElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgComponentTransferFunctionElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgDefsElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgDescElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"SvgEllipseElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgFilterElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgForeignObjectElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgGeometryElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgGradientElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgGraphicsElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgImageElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgLength\": [],\n        \"SvgLengthList\": [],\n        \"SvgLineElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgLinearGradientElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGradientElement\"\n        ],\n        \"SvgMarkerElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgMaskElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgMatrix\": [],\n        \"SvgMetadataElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgNumber\": [],\n        \"SvgNumberList\": [],\n        \"SvgPathElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgPathSeg\": [],\n        \"SvgPathSegArcAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegArcRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegClosePath\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoCubicAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoCubicRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoCubicSmoothAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoCubicSmoothRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoQuadraticAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoQuadraticRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoQuadraticSmoothAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegCurvetoQuadraticSmoothRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegLinetoAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegLinetoHorizontalAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegLinetoHorizontalRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegLinetoRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegLinetoVerticalAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegLinetoVerticalRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegList\": [],\n        \"SvgPathSegMovetoAbs\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPathSegMovetoRel\": [\n          \"SvgPathSeg\"\n        ],\n        \"SvgPatternElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgPoint\": [],\n        \"SvgPointList\": [],\n        \"SvgPolygonElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgPolylineElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgPreserveAspectRatio\": [],\n        \"SvgRadialGradientElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGradientElement\"\n        ],\n        \"SvgRect\": [],\n        \"SvgRectElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGeometryElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgScriptElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgSetElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgAnimationElement\",\n          \"SvgElement\"\n        ],\n        \"SvgStopElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgStringList\": [],\n        \"SvgStyleElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgSwitchElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgSymbolElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgTextContentElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgTextElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\",\n          \"SvgTextContentElement\",\n          \"SvgTextPositioningElement\"\n        ],\n        \"SvgTextPathElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\",\n          \"SvgTextContentElement\"\n        ],\n        \"SvgTextPositioningElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\",\n          \"SvgTextContentElement\"\n        ],\n        \"SvgTitleElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgTransform\": [],\n        \"SvgTransformList\": [],\n        \"SvgUnitTypes\": [],\n        \"SvgUseElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgViewElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgZoomAndPan\": [],\n        \"SvgaElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgfeBlendElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeColorMatrixElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeComponentTransferElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeCompositeElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeConvolveMatrixElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeDiffuseLightingElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeDisplacementMapElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeDistantLightElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeDropShadowElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeFloodElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeFuncAElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgComponentTransferFunctionElement\",\n          \"SvgElement\"\n        ],\n        \"SvgfeFuncBElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgComponentTransferFunctionElement\",\n          \"SvgElement\"\n        ],\n        \"SvgfeFuncGElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgComponentTransferFunctionElement\",\n          \"SvgElement\"\n        ],\n        \"SvgfeFuncRElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgComponentTransferFunctionElement\",\n          \"SvgElement\"\n        ],\n        \"SvgfeGaussianBlurElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeImageElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeMergeElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeMergeNodeElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeMorphologyElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeOffsetElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfePointLightElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeSpecularLightingElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeSpotLightElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeTileElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgfeTurbulenceElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvggElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgmPathElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\"\n        ],\n        \"SvgsvgElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\"\n        ],\n        \"SvgtSpanElement\": [\n          \"Element\",\n          \"EventTarget\",\n          \"Node\",\n          \"SvgElement\",\n          \"SvgGraphicsElement\",\n          \"SvgTextContentElement\",\n          \"SvgTextPositioningElement\"\n        ],\n        \"TcpReadyState\": [],\n        \"TcpServerSocket\": [\n          \"EventTarget\"\n        ],\n        \"TcpServerSocketEvent\": [\n          \"Event\"\n        ],\n        \"TcpServerSocketEventInit\": [],\n        \"TcpSocket\": [\n          \"EventTarget\"\n        ],\n        \"TcpSocketBinaryType\": [],\n        \"TcpSocketErrorEvent\": [\n          \"Event\"\n        ],\n        \"TcpSocketErrorEventInit\": [],\n        \"TcpSocketEvent\": [\n          \"Event\"\n        ],\n        \"TcpSocketEventInit\": [],\n        \"Text\": [\n          \"CharacterData\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"TextDecodeOptions\": [],\n        \"TextDecoder\": [],\n        \"TextDecoderOptions\": [],\n        \"TextEncoder\": [],\n        \"TextMetrics\": [],\n        \"TextTrack\": [\n          \"EventTarget\"\n        ],\n        \"TextTrackCue\": [\n          \"EventTarget\"\n        ],\n        \"TextTrackCueList\": [],\n        \"TextTrackKind\": [],\n        \"TextTrackList\": [\n          \"EventTarget\"\n        ],\n        \"TextTrackMode\": [],\n        \"TimeEvent\": [\n          \"Event\"\n        ],\n        \"TimeRanges\": [],\n        \"Touch\": [],\n        \"TouchEvent\": [\n          \"Event\",\n          \"UiEvent\"\n        ],\n        \"TouchEventInit\": [],\n        \"TouchInit\": [],\n        \"TouchList\": [],\n        \"TrackEvent\": [\n          \"Event\"\n        ],\n        \"TrackEventInit\": [],\n        \"TransformStream\": [],\n        \"TransitionEvent\": [\n          \"Event\"\n        ],\n        \"TransitionEventInit\": [],\n        \"Transport\": [],\n        \"TreeBoxObject\": [],\n        \"TreeCellInfo\": [],\n        \"TreeView\": [],\n        \"TreeWalker\": [],\n        \"U2f\": [],\n        \"U2fClientData\": [],\n        \"UdpMessageEventInit\": [],\n        \"UdpOptions\": [],\n        \"UiEvent\": [\n          \"Event\"\n        ],\n        \"UiEventInit\": [],\n        \"Url\": [],\n        \"UrlSearchParams\": [],\n        \"Usb\": [\n          \"EventTarget\"\n        ],\n        \"UsbAlternateInterface\": [],\n        \"UsbConfiguration\": [],\n        \"UsbConnectionEvent\": [\n          \"Event\"\n        ],\n        \"UsbConnectionEventInit\": [],\n        \"UsbControlTransferParameters\": [],\n        \"UsbDevice\": [],\n        \"UsbDeviceFilter\": [],\n        \"UsbDeviceRequestOptions\": [],\n        \"UsbDirection\": [],\n        \"UsbEndpoint\": [],\n        \"UsbEndpointType\": [],\n        \"UsbInTransferResult\": [],\n        \"UsbInterface\": [],\n        \"UsbIsochronousInTransferPacket\": [],\n        \"UsbIsochronousInTransferResult\": [],\n        \"UsbIsochronousOutTransferPacket\": [],\n        \"UsbIsochronousOutTransferResult\": [],\n        \"UsbOutTransferResult\": [],\n        \"UsbPermissionDescriptor\": [],\n        \"UsbPermissionResult\": [\n          \"EventTarget\",\n          \"PermissionStatus\"\n        ],\n        \"UsbPermissionStorage\": [],\n        \"UsbRecipient\": [],\n        \"UsbRequestType\": [],\n        \"UsbTransferStatus\": [],\n        \"UserProximityEvent\": [\n          \"Event\"\n        ],\n        \"UserProximityEventInit\": [],\n        \"UserVerificationRequirement\": [],\n        \"ValidityState\": [],\n        \"ValueEvent\": [\n          \"Event\"\n        ],\n        \"ValueEventInit\": [],\n        \"VideoColorPrimaries\": [],\n        \"VideoColorSpace\": [],\n        \"VideoColorSpaceInit\": [],\n        \"VideoConfiguration\": [],\n        \"VideoDecoder\": [],\n        \"VideoDecoderConfig\": [],\n        \"VideoDecoderInit\": [],\n        \"VideoDecoderSupport\": [],\n        \"VideoEncoder\": [],\n        \"VideoEncoderConfig\": [],\n        \"VideoEncoderEncodeOptions\": [],\n        \"VideoEncoderInit\": [],\n        \"VideoEncoderSupport\": [],\n        \"VideoFacingModeEnum\": [],\n        \"VideoFrame\": [],\n        \"VideoFrameBufferInit\": [],\n        \"VideoFrameCopyToOptions\": [],\n        \"VideoFrameInit\": [],\n        \"VideoMatrixCoefficients\": [],\n        \"VideoPixelFormat\": [],\n        \"VideoPlaybackQuality\": [],\n        \"VideoStreamTrack\": [\n          \"EventTarget\",\n          \"MediaStreamTrack\"\n        ],\n        \"VideoTrack\": [],\n        \"VideoTrackList\": [\n          \"EventTarget\"\n        ],\n        \"VideoTransferCharacteristics\": [],\n        \"VisibilityState\": [],\n        \"VoidCallback\": [],\n        \"VrDisplay\": [\n          \"EventTarget\"\n        ],\n        \"VrDisplayCapabilities\": [],\n        \"VrEye\": [],\n        \"VrEyeParameters\": [],\n        \"VrFieldOfView\": [],\n        \"VrFrameData\": [],\n        \"VrLayer\": [],\n        \"VrMockController\": [],\n        \"VrMockDisplay\": [],\n        \"VrPose\": [],\n        \"VrServiceTest\": [],\n        \"VrStageParameters\": [],\n        \"VrSubmitFrameResult\": [],\n        \"VttCue\": [\n          \"EventTarget\",\n          \"TextTrackCue\"\n        ],\n        \"VttRegion\": [],\n        \"WakeLock\": [],\n        \"WakeLockSentinel\": [\n          \"EventTarget\"\n        ],\n        \"WakeLockType\": [],\n        \"WatchAdvertisementsOptions\": [],\n        \"WaveShaperNode\": [\n          \"AudioNode\",\n          \"EventTarget\"\n        ],\n        \"WaveShaperOptions\": [],\n        \"WebGl2RenderingContext\": [],\n        \"WebGlActiveInfo\": [],\n        \"WebGlBuffer\": [],\n        \"WebGlContextAttributes\": [],\n        \"WebGlContextEvent\": [\n          \"Event\"\n        ],\n        \"WebGlContextEventInit\": [],\n        \"WebGlFramebuffer\": [],\n        \"WebGlPowerPreference\": [],\n        \"WebGlProgram\": [],\n        \"WebGlQuery\": [],\n        \"WebGlRenderbuffer\": [],\n        \"WebGlRenderingContext\": [],\n        \"WebGlSampler\": [],\n        \"WebGlShader\": [],\n        \"WebGlShaderPrecisionFormat\": [],\n        \"WebGlSync\": [],\n        \"WebGlTexture\": [],\n        \"WebGlTransformFeedback\": [],\n        \"WebGlUniformLocation\": [],\n        \"WebGlVertexArrayObject\": [],\n        \"WebKitCssMatrix\": [\n          \"DomMatrix\",\n          \"DomMatrixReadOnly\"\n        ],\n        \"WebSocket\": [\n          \"EventTarget\"\n        ],\n        \"WebSocketDict\": [],\n        \"WebSocketElement\": [],\n        \"WebglColorBufferFloat\": [],\n        \"WebglCompressedTextureAstc\": [],\n        \"WebglCompressedTextureAtc\": [],\n        \"WebglCompressedTextureEtc\": [],\n        \"WebglCompressedTextureEtc1\": [],\n        \"WebglCompressedTexturePvrtc\": [],\n        \"WebglCompressedTextureS3tc\": [],\n        \"WebglCompressedTextureS3tcSrgb\": [],\n        \"WebglDebugRendererInfo\": [],\n        \"WebglDebugShaders\": [],\n        \"WebglDepthTexture\": [],\n        \"WebglDrawBuffers\": [],\n        \"WebglLoseContext\": [],\n        \"WebrtcGlobalStatisticsReport\": [],\n        \"WheelEvent\": [\n          \"Event\",\n          \"MouseEvent\",\n          \"UiEvent\"\n        ],\n        \"WheelEventInit\": [],\n        \"WidevineCdmManifest\": [],\n        \"Window\": [\n          \"EventTarget\"\n        ],\n        \"WindowClient\": [\n          \"Client\"\n        ],\n        \"Worker\": [\n          \"EventTarget\"\n        ],\n        \"WorkerDebuggerGlobalScope\": [\n          \"EventTarget\"\n        ],\n        \"WorkerGlobalScope\": [\n          \"EventTarget\"\n        ],\n        \"WorkerLocation\": [],\n        \"WorkerNavigator\": [],\n        \"WorkerOptions\": [],\n        \"WorkerType\": [],\n        \"Worklet\": [],\n        \"WorkletGlobalScope\": [],\n        \"WorkletOptions\": [],\n        \"WritableStream\": [],\n        \"WritableStreamDefaultWriter\": [],\n        \"XPathExpression\": [],\n        \"XPathNsResolver\": [],\n        \"XPathResult\": [],\n        \"XmlDocument\": [\n          \"Document\",\n          \"EventTarget\",\n          \"Node\"\n        ],\n        \"XmlHttpRequest\": [\n          \"EventTarget\",\n          \"XmlHttpRequestEventTarget\"\n        ],\n        \"XmlHttpRequestEventTarget\": [\n          \"EventTarget\"\n        ],\n        \"XmlHttpRequestResponseType\": [],\n        \"XmlHttpRequestUpload\": [\n          \"EventTarget\",\n          \"XmlHttpRequestEventTarget\"\n        ],\n        \"XmlSerializer\": [],\n        \"Xr\": [\n          \"EventTarget\"\n        ],\n        \"XrBoundedReferenceSpace\": [\n          \"EventTarget\",\n          \"XrReferenceSpace\",\n          \"XrSpace\"\n        ],\n        \"XrEye\": [],\n        \"XrFrame\": [],\n        \"XrHandedness\": [],\n        \"XrInputSource\": [],\n        \"XrInputSourceArray\": [],\n        \"XrInputSourceEvent\": [\n          \"Event\"\n        ],\n        \"XrInputSourceEventInit\": [],\n        \"XrInputSourcesChangeEvent\": [\n          \"Event\"\n        ],\n        \"XrInputSourcesChangeEventInit\": [],\n        \"XrPose\": [],\n        \"XrReferenceSpace\": [\n          \"EventTarget\",\n          \"XrSpace\"\n        ],\n        \"XrReferenceSpaceEvent\": [\n          \"Event\"\n        ],\n        \"XrReferenceSpaceEventInit\": [],\n        \"XrReferenceSpaceType\": [],\n        \"XrRenderState\": [],\n        \"XrRenderStateInit\": [],\n        \"XrRigidTransform\": [],\n        \"XrSession\": [\n          \"EventTarget\"\n        ],\n        \"XrSessionEvent\": [\n          \"Event\"\n        ],\n        \"XrSessionEventInit\": [],\n        \"XrSessionInit\": [],\n        \"XrSessionMode\": [],\n        \"XrSpace\": [\n          \"EventTarget\"\n        ],\n        \"XrTargetRayMode\": [],\n        \"XrView\": [],\n        \"XrViewerPose\": [\n          \"XrPose\"\n        ],\n        \"XrViewport\": [],\n        \"XrVisibilityState\": [],\n        \"XrWebGlLayer\": [],\n        \"XrWebGlLayerInit\": [],\n        \"XsltProcessor\": [],\n        \"console\": [],\n        \"css\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/web-sys-0.3.57/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"all-features\": true,\n            \"rustdoc-args\": [\n              \"--cfg=web_sys_unstable_apis\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"The wasm-bindgen Developers\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"./README.md\",\n      \"repository\": \"https://github.com/rustwasm/wasm-bindgen/tree/master/crates/web-sys\",\n      \"homepage\": \"https://rustwasm.github.io/wasm-bindgen/web-sys/index.html\",\n      \"documentation\": \"https://rustwasm.github.io/wasm-bindgen/api/web_sys/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"webpki\",\n      \"version\": \"0.21.4\",\n      \"id\": \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": null,\n      \"license_file\": \"LICENSE\",\n      \"description\": \"Web PKI X.509 Certificate Verification.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"ring\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.16.19\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": false,\n          \"features\": [\n            \"alloc\"\n          ],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"untrusted\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.7.1\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        },\n        {\n          \"name\": \"base64\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.9.1\",\n          \"kind\": \"dev\",\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"webpki\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-0.21.4/src/webpki.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"integration\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-0.21.4/tests/integration.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"test\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"dns_name_tests\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-0.21.4/tests/dns_name_tests.rs\",\n          \"edition\": \"2018\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {\n        \"default\": [\n          \"std\",\n          \"trust_anchor_util\"\n        ],\n        \"std\": [],\n        \"trust_anchor_util\": [\n          \"std\"\n        ]\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-0.21.4/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Brian Smith <brian@briansmith.org>\"\n      ],\n      \"categories\": [\n        \"cryptography\",\n        \"no-std\"\n      ],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/briansmith/webpki\",\n      \"homepage\": null,\n      \"documentation\": \"https://briansmith.org/rustdoc/webpki/\",\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"webpki-roots\",\n      \"version\": \"0.21.1\",\n      \"id\": \"webpki-roots 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MPL-2.0\",\n      \"license_file\": null,\n      \"description\": \"Mozilla's CA root certificates for use with webpki\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"webpki\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.21.0\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": null,\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"webpki-roots\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-roots-0.21.1/src/lib.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"bin\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"process_cert\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-roots-0.21.1/src/bin/process_cert.rs\",\n          \"edition\": \"2018\",\n          \"doc\": true,\n          \"doctest\": false,\n          \"test\": true\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/webpki-roots-0.21.1/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Joseph Birr-Pixton <jpixton@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/ctz/webpki-roots\",\n      \"homepage\": \"https://github.com/ctz/webpki-roots\",\n      \"documentation\": null,\n      \"edition\": \"2018\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"winapi\",\n      \"version\": \"0.3.9\",\n      \"id\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Raw FFI bindings for all of Windows API.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [\n        {\n          \"name\": \"winapi-i686-pc-windows-gnu\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"i686-pc-windows-gnu\",\n          \"registry\": null\n        },\n        {\n          \"name\": \"winapi-x86_64-pc-windows-gnu\",\n          \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n          \"req\": \"^0.4\",\n          \"kind\": null,\n          \"rename\": null,\n          \"optional\": false,\n          \"uses_default_features\": true,\n          \"features\": [],\n          \"target\": \"x86_64-pc-windows-gnu\",\n          \"registry\": null\n        }\n      ],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"winapi\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-0.3.9/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-0.3.9/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {\n        \"accctrl\": [],\n        \"aclapi\": [],\n        \"activation\": [],\n        \"adhoc\": [],\n        \"appmgmt\": [],\n        \"audioclient\": [],\n        \"audiosessiontypes\": [],\n        \"avrt\": [],\n        \"basetsd\": [],\n        \"bcrypt\": [],\n        \"bits\": [],\n        \"bits10_1\": [],\n        \"bits1_5\": [],\n        \"bits2_0\": [],\n        \"bits2_5\": [],\n        \"bits3_0\": [],\n        \"bits4_0\": [],\n        \"bits5_0\": [],\n        \"bitscfg\": [],\n        \"bitsmsg\": [],\n        \"bluetoothapis\": [],\n        \"bluetoothleapis\": [],\n        \"bthdef\": [],\n        \"bthioctl\": [],\n        \"bthledef\": [],\n        \"bthsdpdef\": [],\n        \"bugcodes\": [],\n        \"cderr\": [],\n        \"cfg\": [],\n        \"cfgmgr32\": [],\n        \"cguid\": [],\n        \"combaseapi\": [],\n        \"coml2api\": [],\n        \"commapi\": [],\n        \"commctrl\": [],\n        \"commdlg\": [],\n        \"commoncontrols\": [],\n        \"consoleapi\": [],\n        \"corecrt\": [],\n        \"corsym\": [],\n        \"d2d1\": [],\n        \"d2d1_1\": [],\n        \"d2d1_2\": [],\n        \"d2d1_3\": [],\n        \"d2d1effectauthor\": [],\n        \"d2d1effects\": [],\n        \"d2d1effects_1\": [],\n        \"d2d1effects_2\": [],\n        \"d2d1svg\": [],\n        \"d2dbasetypes\": [],\n        \"d3d\": [],\n        \"d3d10\": [],\n        \"d3d10_1\": [],\n        \"d3d10_1shader\": [],\n        \"d3d10effect\": [],\n        \"d3d10misc\": [],\n        \"d3d10sdklayers\": [],\n        \"d3d10shader\": [],\n        \"d3d11\": [],\n        \"d3d11_1\": [],\n        \"d3d11_2\": [],\n        \"d3d11_3\": [],\n        \"d3d11_4\": [],\n        \"d3d11on12\": [],\n        \"d3d11sdklayers\": [],\n        \"d3d11shader\": [],\n        \"d3d11tokenizedprogramformat\": [],\n        \"d3d12\": [],\n        \"d3d12sdklayers\": [],\n        \"d3d12shader\": [],\n        \"d3d9\": [],\n        \"d3d9caps\": [],\n        \"d3d9types\": [],\n        \"d3dcommon\": [],\n        \"d3dcompiler\": [],\n        \"d3dcsx\": [],\n        \"d3dkmdt\": [],\n        \"d3dkmthk\": [],\n        \"d3dukmdt\": [],\n        \"d3dx10core\": [],\n        \"d3dx10math\": [],\n        \"d3dx10mesh\": [],\n        \"datetimeapi\": [],\n        \"davclnt\": [],\n        \"dbghelp\": [],\n        \"dbt\": [],\n        \"dcommon\": [],\n        \"dcomp\": [],\n        \"dcompanimation\": [],\n        \"dcomptypes\": [],\n        \"dde\": [],\n        \"ddraw\": [],\n        \"ddrawi\": [],\n        \"ddrawint\": [],\n        \"debug\": [\n          \"impl-debug\"\n        ],\n        \"debugapi\": [],\n        \"devguid\": [],\n        \"devicetopology\": [],\n        \"devpkey\": [],\n        \"devpropdef\": [],\n        \"dinput\": [],\n        \"dinputd\": [],\n        \"dispex\": [],\n        \"dmksctl\": [],\n        \"dmusicc\": [],\n        \"docobj\": [],\n        \"documenttarget\": [],\n        \"dot1x\": [],\n        \"dpa_dsa\": [],\n        \"dpapi\": [],\n        \"dsgetdc\": [],\n        \"dsound\": [],\n        \"dsrole\": [],\n        \"dvp\": [],\n        \"dwmapi\": [],\n        \"dwrite\": [],\n        \"dwrite_1\": [],\n        \"dwrite_2\": [],\n        \"dwrite_3\": [],\n        \"dxdiag\": [],\n        \"dxfile\": [],\n        \"dxgi\": [],\n        \"dxgi1_2\": [],\n        \"dxgi1_3\": [],\n        \"dxgi1_4\": [],\n        \"dxgi1_5\": [],\n        \"dxgi1_6\": [],\n        \"dxgidebug\": [],\n        \"dxgiformat\": [],\n        \"dxgitype\": [],\n        \"dxva2api\": [],\n        \"dxvahd\": [],\n        \"eaptypes\": [],\n        \"enclaveapi\": [],\n        \"endpointvolume\": [],\n        \"errhandlingapi\": [],\n        \"everything\": [],\n        \"evntcons\": [],\n        \"evntprov\": [],\n        \"evntrace\": [],\n        \"excpt\": [],\n        \"exdisp\": [],\n        \"fibersapi\": [],\n        \"fileapi\": [],\n        \"functiondiscoverykeys_devpkey\": [],\n        \"gl-gl\": [],\n        \"guiddef\": [],\n        \"handleapi\": [],\n        \"heapapi\": [],\n        \"hidclass\": [],\n        \"hidpi\": [],\n        \"hidsdi\": [],\n        \"hidusage\": [],\n        \"highlevelmonitorconfigurationapi\": [],\n        \"hstring\": [],\n        \"http\": [],\n        \"ifdef\": [],\n        \"ifmib\": [],\n        \"imm\": [],\n        \"impl-debug\": [],\n        \"impl-default\": [],\n        \"in6addr\": [],\n        \"inaddr\": [],\n        \"inspectable\": [],\n        \"interlockedapi\": [],\n        \"intsafe\": [],\n        \"ioapiset\": [],\n        \"ipexport\": [],\n        \"iphlpapi\": [],\n        \"ipifcons\": [],\n        \"ipmib\": [],\n        \"iprtrmib\": [],\n        \"iptypes\": [],\n        \"jobapi\": [],\n        \"jobapi2\": [],\n        \"knownfolders\": [],\n        \"ks\": [],\n        \"ksmedia\": [],\n        \"ktmtypes\": [],\n        \"ktmw32\": [],\n        \"l2cmn\": [],\n        \"libloaderapi\": [],\n        \"limits\": [],\n        \"lmaccess\": [],\n        \"lmalert\": [],\n        \"lmapibuf\": [],\n        \"lmat\": [],\n        \"lmcons\": [],\n        \"lmdfs\": [],\n        \"lmerrlog\": [],\n        \"lmjoin\": [],\n        \"lmmsg\": [],\n        \"lmremutl\": [],\n        \"lmrepl\": [],\n        \"lmserver\": [],\n        \"lmshare\": [],\n        \"lmstats\": [],\n        \"lmsvc\": [],\n        \"lmuse\": [],\n        \"lmwksta\": [],\n        \"lowlevelmonitorconfigurationapi\": [],\n        \"lsalookup\": [],\n        \"memoryapi\": [],\n        \"minschannel\": [],\n        \"minwinbase\": [],\n        \"minwindef\": [],\n        \"mmdeviceapi\": [],\n        \"mmeapi\": [],\n        \"mmreg\": [],\n        \"mmsystem\": [],\n        \"mprapidef\": [],\n        \"msaatext\": [],\n        \"mscat\": [],\n        \"mschapp\": [],\n        \"mssip\": [],\n        \"mstcpip\": [],\n        \"mswsock\": [],\n        \"mswsockdef\": [],\n        \"namedpipeapi\": [],\n        \"namespaceapi\": [],\n        \"nb30\": [],\n        \"ncrypt\": [],\n        \"netioapi\": [],\n        \"nldef\": [],\n        \"ntddndis\": [],\n        \"ntddscsi\": [],\n        \"ntddser\": [],\n        \"ntdef\": [],\n        \"ntlsa\": [],\n        \"ntsecapi\": [],\n        \"ntstatus\": [],\n        \"oaidl\": [],\n        \"objbase\": [],\n        \"objidl\": [],\n        \"objidlbase\": [],\n        \"ocidl\": [],\n        \"ole2\": [],\n        \"oleauto\": [],\n        \"olectl\": [],\n        \"oleidl\": [],\n        \"opmapi\": [],\n        \"pdh\": [],\n        \"perflib\": [],\n        \"physicalmonitorenumerationapi\": [],\n        \"playsoundapi\": [],\n        \"portabledevice\": [],\n        \"portabledeviceapi\": [],\n        \"portabledevicetypes\": [],\n        \"powerbase\": [],\n        \"powersetting\": [],\n        \"powrprof\": [],\n        \"processenv\": [],\n        \"processsnapshot\": [],\n        \"processthreadsapi\": [],\n        \"processtopologyapi\": [],\n        \"profileapi\": [],\n        \"propidl\": [],\n        \"propkey\": [],\n        \"propkeydef\": [],\n        \"propsys\": [],\n        \"prsht\": [],\n        \"psapi\": [],\n        \"qos\": [],\n        \"realtimeapiset\": [],\n        \"reason\": [],\n        \"restartmanager\": [],\n        \"restrictederrorinfo\": [],\n        \"rmxfguid\": [],\n        \"roapi\": [],\n        \"robuffer\": [],\n        \"roerrorapi\": [],\n        \"rpc\": [],\n        \"rpcdce\": [],\n        \"rpcndr\": [],\n        \"rtinfo\": [],\n        \"sapi\": [],\n        \"sapi51\": [],\n        \"sapi53\": [],\n        \"sapiddk\": [],\n        \"sapiddk51\": [],\n        \"schannel\": [],\n        \"sddl\": [],\n        \"securityappcontainer\": [],\n        \"securitybaseapi\": [],\n        \"servprov\": [],\n        \"setupapi\": [],\n        \"shellapi\": [],\n        \"shellscalingapi\": [],\n        \"shlobj\": [],\n        \"shobjidl\": [],\n        \"shobjidl_core\": [],\n        \"shtypes\": [],\n        \"softpub\": [],\n        \"spapidef\": [],\n        \"spellcheck\": [],\n        \"sporder\": [],\n        \"sql\": [],\n        \"sqlext\": [],\n        \"sqltypes\": [],\n        \"sqlucode\": [],\n        \"sspi\": [],\n        \"std\": [],\n        \"stralign\": [],\n        \"stringapiset\": [],\n        \"strmif\": [],\n        \"subauth\": [],\n        \"synchapi\": [],\n        \"sysinfoapi\": [],\n        \"systemtopologyapi\": [],\n        \"taskschd\": [],\n        \"tcpestats\": [],\n        \"tcpmib\": [],\n        \"textstor\": [],\n        \"threadpoolapiset\": [],\n        \"threadpoollegacyapiset\": [],\n        \"timeapi\": [],\n        \"timezoneapi\": [],\n        \"tlhelp32\": [],\n        \"transportsettingcommon\": [],\n        \"tvout\": [],\n        \"udpmib\": [],\n        \"unknwnbase\": [],\n        \"urlhist\": [],\n        \"urlmon\": [],\n        \"usb\": [],\n        \"usbioctl\": [],\n        \"usbiodef\": [],\n        \"usbscan\": [],\n        \"usbspec\": [],\n        \"userenv\": [],\n        \"usp10\": [],\n        \"utilapiset\": [],\n        \"uxtheme\": [],\n        \"vadefs\": [],\n        \"vcruntime\": [],\n        \"vsbackup\": [],\n        \"vss\": [],\n        \"vsserror\": [],\n        \"vswriter\": [],\n        \"wbemads\": [],\n        \"wbemcli\": [],\n        \"wbemdisp\": [],\n        \"wbemprov\": [],\n        \"wbemtran\": [],\n        \"wct\": [],\n        \"werapi\": [],\n        \"winbase\": [],\n        \"wincodec\": [],\n        \"wincodecsdk\": [],\n        \"wincon\": [],\n        \"wincontypes\": [],\n        \"wincred\": [],\n        \"wincrypt\": [],\n        \"windef\": [],\n        \"windot11\": [],\n        \"windowsceip\": [],\n        \"windowsx\": [],\n        \"winefs\": [],\n        \"winerror\": [],\n        \"winevt\": [],\n        \"wingdi\": [],\n        \"winhttp\": [],\n        \"wininet\": [],\n        \"winineti\": [],\n        \"winioctl\": [],\n        \"winnetwk\": [],\n        \"winnls\": [],\n        \"winnt\": [],\n        \"winreg\": [],\n        \"winsafer\": [],\n        \"winscard\": [],\n        \"winsmcrd\": [],\n        \"winsock2\": [],\n        \"winspool\": [],\n        \"winstring\": [],\n        \"winsvc\": [],\n        \"wintrust\": [],\n        \"winusb\": [],\n        \"winusbio\": [],\n        \"winuser\": [],\n        \"winver\": [],\n        \"wlanapi\": [],\n        \"wlanihv\": [],\n        \"wlanihvtypes\": [],\n        \"wlantypes\": [],\n        \"wlclient\": [],\n        \"wmistr\": [],\n        \"wnnc\": [],\n        \"wow64apiset\": [],\n        \"wpdmtpextensions\": [],\n        \"ws2bth\": [],\n        \"ws2def\": [],\n        \"ws2ipdef\": [],\n        \"ws2spi\": [],\n        \"ws2tcpip\": [],\n        \"wtsapi32\": [],\n        \"wtypes\": [],\n        \"wtypesbase\": [],\n        \"xinput\": []\n      },\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-0.3.9/Cargo.toml\",\n      \"metadata\": {\n        \"docs\": {\n          \"rs\": {\n            \"default-target\": \"x86_64-pc-windows-msvc\",\n            \"features\": [\n              \"everything\",\n              \"impl-debug\",\n              \"impl-default\"\n            ],\n            \"targets\": [\n              \"aarch64-pc-windows-msvc\",\n              \"i686-pc-windows-msvc\",\n              \"x86_64-pc-windows-msvc\"\n            ]\n          }\n        }\n      },\n      \"publish\": null,\n      \"authors\": [\n        \"Peter Atashian <retep998@gmail.com>\"\n      ],\n      \"categories\": [\n        \"external-ffi-bindings\",\n        \"no-std\",\n        \"os::windows-apis\"\n      ],\n      \"keywords\": [\n        \"windows\",\n        \"ffi\",\n        \"win32\",\n        \"com\",\n        \"directx\"\n      ],\n      \"readme\": \"README.md\",\n      \"repository\": \"https://github.com/retep998/winapi-rs\",\n      \"homepage\": null,\n      \"documentation\": \"https://docs.rs/winapi/\",\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"winapi-i686-pc-windows-gnu\",\n      \"version\": \"0.4.0\",\n      \"id\": \"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Import libraries for the i686-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"winapi-i686-pc-windows-gnu\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-i686-pc-windows-gnu-0.4.0/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-i686-pc-windows-gnu-0.4.0/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-i686-pc-windows-gnu-0.4.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Peter Atashian <retep998@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"windows\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/retep998/winapi-rs\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    },\n    {\n      \"name\": \"winapi-x86_64-pc-windows-gnu\",\n      \"version\": \"0.4.0\",\n      \"id\": \"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n      \"license\": \"MIT/Apache-2.0\",\n      \"license_file\": null,\n      \"description\": \"Import libraries for the x86_64-pc-windows-gnu target. Please don't use this crate directly, depend on winapi instead.\",\n      \"source\": \"registry+https://github.com/rust-lang/crates.io-index\",\n      \"dependencies\": [],\n      \"targets\": [\n        {\n          \"kind\": [\n            \"lib\"\n          ],\n          \"crate_types\": [\n            \"lib\"\n          ],\n          \"name\": \"winapi-x86_64-pc-windows-gnu\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-x86_64-pc-windows-gnu-0.4.0/src/lib.rs\",\n          \"edition\": \"2015\",\n          \"doc\": true,\n          \"doctest\": true,\n          \"test\": true\n        },\n        {\n          \"kind\": [\n            \"custom-build\"\n          ],\n          \"crate_types\": [\n            \"bin\"\n          ],\n          \"name\": \"build-script-build\",\n          \"src_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-x86_64-pc-windows-gnu-0.4.0/build.rs\",\n          \"edition\": \"2015\",\n          \"doc\": false,\n          \"doctest\": false,\n          \"test\": false\n        }\n      ],\n      \"features\": {},\n      \"manifest_path\": \"/home/user/.data/cargo/registry/src/github.com-1ecc6299db9ec823/winapi-x86_64-pc-windows-gnu-0.4.0/Cargo.toml\",\n      \"metadata\": null,\n      \"publish\": null,\n      \"authors\": [\n        \"Peter Atashian <retep998@gmail.com>\"\n      ],\n      \"categories\": [],\n      \"keywords\": [\n        \"windows\"\n      ],\n      \"readme\": null,\n      \"repository\": \"https://github.com/retep998/winapi-rs\",\n      \"homepage\": null,\n      \"documentation\": null,\n      \"edition\": \"2015\",\n      \"links\": null,\n      \"default_run\": null,\n      \"rust_version\": null\n    }\n  ],\n  \"workspace_members\": [\n    \"b_in_workspace_lib 0.1.0 (path+file:///home/user/problematic/workspace/b_in_workspace_lib)\",\n    \"c_in_workspace_bin 0.1.0 (path+file:///home/user/problematic/workspace/c_in_workspace_bin)\"\n  ],\n  \"resolve\": {\n    \"nodes\": [\n      {\n        \"id\": \"ahash 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"getrandom 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"getrandom\",\n            \"pkg\": \"getrandom 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(any(target_os = \\\"linux\\\", target_os = \\\"android\\\", target_os = \\\"windows\\\", target_os = \\\"macos\\\", target_os = \\\"ios\\\", target_os = \\\"freebsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"netbsd\\\", target_os = \\\"dragonfly\\\", target_os = \\\"solaris\\\", target_os = \\\"illumos\\\", target_os = \\\"fuchsia\\\", target_os = \\\"redox\\\", target_os = \\\"cloudabi\\\", target_os = \\\"haiku\\\", target_os = \\\"vxworks\\\", target_os = \\\"emscripten\\\", target_os = \\\"wasi\\\"))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"once_cell\",\n            \"pkg\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"version_check\",\n            \"pkg\": \"version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"atoi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"num_traits\",\n            \"pkg\": \"num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"b_in_workspace_lib 0.1.0 (path+file:///home/user/problematic/workspace/b_in_workspace_lib)\",\n        \"dependencies\": [\n          \"sqlx 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"sqlx\",\n            \"pkg\": \"sqlx 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\"\n        ]\n      },\n      {\n        \"id\": \"block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"generic-array 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"generic_array\",\n            \"pkg\": \"generic-array 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"bumpalo 3.9.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\"\n        ]\n      },\n      {\n        \"id\": \"byteorder 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"bytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"c_in_workspace_bin 0.1.0 (path+file:///home/user/problematic/workspace/c_in_workspace_bin)\",\n        \"dependencies\": [\n          \"b_in_workspace_lib 0.1.0 (path+file:///home/user/problematic/workspace/b_in_workspace_lib)\",\n          \"sqlx 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"b_in_workspace_lib\",\n            \"pkg\": \"b_in_workspace_lib 0.1.0 (path+file:///home/user/problematic/workspace/b_in_workspace_lib)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sqlx\",\n            \"pkg\": \"sqlx 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"cc 1.0.73 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"cpufeatures 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"aarch64-apple-darwin\"\n              },\n              {\n                \"kind\": null,\n                \"target\": \"aarch64-linux-android\"\n              },\n              {\n                \"kind\": null,\n                \"target\": \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\"\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"crc 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"crc-catalog 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"crc_catalog\",\n            \"pkg\": \"crc-catalog 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"crc-catalog 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"crossbeam-queue 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"crossbeam-utils 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"crossbeam_utils\",\n            \"pkg\": \"crossbeam-utils 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"crossbeam-utils 0.8.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"lazy_static\",\n            \"pkg\": \"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"lazy_static\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"generic-array 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"generic_array\",\n            \"pkg\": \"generic-array 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"serde\",\n            \"pkg\": \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"serde\",\n          \"use_std\"\n        ]\n      },\n      {\n        \"id\": \"flume 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"pin-project 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"spin 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_sink\",\n            \"pkg\": \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"pin_project\",\n            \"pkg\": \"pin-project 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"spin1\",\n            \"pkg\": \"spin 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"async\",\n          \"futures-core\",\n          \"futures-sink\",\n          \"pin-project\"\n        ]\n      },\n      {\n        \"id\": \"form_urlencoded 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"matches\",\n            \"pkg\": \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"percent_encoding\",\n            \"pkg\": \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"futures-channel 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_sink\",\n            \"pkg\": \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"futures-sink\",\n          \"sink\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"futures-executor 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-task 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-util 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_task\",\n            \"pkg\": \"futures-task 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_util\",\n            \"pkg\": \"futures-util 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"futures-intrusive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"parking_lot 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"lock_api\",\n            \"pkg\": \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"parking_lot\",\n            \"pkg\": \"parking_lot 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"parking_lot\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"futures-task 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"alloc\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"futures-util 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-task 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"slab 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_sink\",\n            \"pkg\": \"futures-sink 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_task\",\n            \"pkg\": \"futures-task 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"pin_project_lite\",\n            \"pkg\": \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"pin_utils\",\n            \"pkg\": \"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"slab\",\n            \"pkg\": \"slab 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"futures-sink\",\n          \"sink\",\n          \"slab\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"generic-array 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"typenum 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"typenum\",\n            \"pkg\": \"typenum 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"version_check\",\n            \"pkg\": \"version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"getrandom 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasi 0.10.2+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(unix)\"\n              }\n            ]\n          },\n          {\n            \"name\": \"wasi\",\n            \"pkg\": \"wasi 0.10.2+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(target_os = \\\"wasi\\\")\"\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"hashbrown 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"ahash 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"ahash\",\n            \"pkg\": \"ahash 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"ahash\",\n          \"default\",\n          \"inline-more\",\n          \"raw\"\n        ]\n      },\n      {\n        \"id\": \"hashlink 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"hashbrown 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"hashbrown\",\n            \"pkg\": \"hashbrown 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"heck 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"unicode-segmentation 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"unicode_segmentation\",\n            \"pkg\": \"unicode-segmentation 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\"\n        ]\n      },\n      {\n        \"id\": \"hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"idna 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"unicode-bidi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"unicode-normalization 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"matches\",\n            \"pkg\": \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"unicode_bidi\",\n            \"pkg\": \"unicode-bidi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"unicode_normalization\",\n            \"pkg\": \"unicode-normalization 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"indexmap 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"hashbrown 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"autocfg\",\n            \"pkg\": \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"hashbrown\",\n            \"pkg\": \"hashbrown 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"itertools 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"either\",\n            \"pkg\": \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"use_alloc\",\n          \"use_std\"\n        ]\n      },\n      {\n        \"id\": \"itoa 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"js-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"wasm-bindgen 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"wasm_bindgen\",\n            \"pkg\": \"wasm-bindgen 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"libsqlite3-sys 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cc 1.0.73 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"pkg-config 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"vcpkg 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cc\",\n            \"pkg\": \"cc 1.0.73 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"pkg_config\",\n            \"pkg\": \"pkg-config 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"vcpkg\",\n            \"pkg\": \"vcpkg 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"bundled\",\n          \"bundled_bindings\",\n          \"cc\",\n          \"pkg-config\",\n          \"unlock_notify\",\n          \"vcpkg\"\n        ]\n      },\n      {\n        \"id\": \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"autocfg\",\n            \"pkg\": \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"scopeguard\",\n            \"pkg\": \"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"minimal-lexical 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"mio 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"miow 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"ntapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(unix)\"\n              },\n              {\n                \"kind\": null,\n                \"target\": \"cfg(target_os = \\\"wasi\\\")\"\n              }\n            ]\n          },\n          {\n            \"name\": \"log\",\n            \"pkg\": \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"miow\",\n            \"pkg\": \"miow 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(windows)\"\n              }\n            ]\n          },\n          {\n            \"name\": \"ntapi\",\n            \"pkg\": \"ntapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(windows)\"\n              }\n            ]\n          },\n          {\n            \"name\": \"wasi\",\n            \"pkg\": \"wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(target_os = \\\"wasi\\\")\"\n              }\n            ]\n          },\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(windows)\"\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"net\",\n          \"os-ext\",\n          \"os-poll\"\n        ]\n      },\n      {\n        \"id\": \"miow 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"nom 7.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"minimal-lexical 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"memchr\",\n            \"pkg\": \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"minimal_lexical\",\n            \"pkg\": \"minimal-lexical 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"ntapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"user\"\n        ]\n      },\n      {\n        \"id\": \"num-traits 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"autocfg\",\n            \"pkg\": \"autocfg 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"num_cpus 1.13.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"hermit_abi\",\n            \"pkg\": \"hermit-abi 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"aarch64\\\"), target_os = \\\"hermit\\\"))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(not(windows))\"\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"race\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"parking_lot 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"parking_lot_core 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"instant\",\n            \"pkg\": \"instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"lock_api\",\n            \"pkg\": \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"parking_lot_core\",\n            \"pkg\": \"parking_lot_core 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\"\n        ]\n      },\n      {\n        \"id\": \"parking_lot_core 0.8.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"redox_syscall 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"smallvec 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"instant\",\n            \"pkg\": \"instant 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(unix)\"\n              }\n            ]\n          },\n          {\n            \"name\": \"syscall\",\n            \"pkg\": \"redox_syscall 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(target_os = \\\"redox\\\")\"\n              }\n            ]\n          },\n          {\n            \"name\": \"smallvec\",\n            \"pkg\": \"smallvec 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(windows)\"\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"paste 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"pin-project 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"pin-project-internal 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"pin_project_internal\",\n            \"pkg\": \"pin-project-internal 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"pin-project-internal 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"syn\",\n            \"pkg\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"pkg-config 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"unicode-xid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"unicode_xid\",\n            \"pkg\": \"unicode-xid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"proc-macro\"\n        ]\n      },\n      {\n        \"id\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"proc-macro\"\n        ]\n      },\n      {\n        \"id\": \"redox_syscall 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"bitflags\",\n            \"pkg\": \"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cc 1.0.73 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"web-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cc\",\n            \"pkg\": \"cc 1.0.73 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": \"build\",\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"once_cell\",\n            \"pkg\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"))\"\n              },\n              {\n                \"kind\": null,\n                \"target\": \"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"illumos\\\", target_os = \\\"netbsd\\\", target_os = \\\"openbsd\\\", target_os = \\\"solaris\\\"))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"spin\",\n            \"pkg\": \"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\", all(any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\"), any(target_os = \\\"android\\\", target_os = \\\"fuchsia\\\", target_os = \\\"linux\\\"))))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"untrusted\",\n            \"pkg\": \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"web_sys\",\n            \"pkg\": \"web-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(all(target_arch = \\\"wasm32\\\", target_vendor = \\\"unknown\\\", target_os = \\\"unknown\\\", target_env = \\\"\\\"))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(target_os = \\\"windows\\\")\"\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"dev_urandom_fallback\",\n          \"once_cell\"\n        ]\n      },\n      {\n        \"id\": \"rustls 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sct 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"base64\",\n            \"pkg\": \"base64 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"log\",\n            \"pkg\": \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"ring\",\n            \"pkg\": \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sct\",\n            \"pkg\": \"sct 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"webpki\",\n            \"pkg\": \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"dangerous_configuration\",\n          \"default\",\n          \"log\",\n          \"logging\"\n        ]\n      },\n      {\n        \"id\": \"ryu 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"sct 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"ring\",\n            \"pkg\": \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"untrusted\",\n            \"pkg\": \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"serde_derive 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"serde_derive\",\n            \"pkg\": \"serde_derive 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"derive\",\n          \"rc\",\n          \"serde_derive\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"serde_derive 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"syn\",\n            \"pkg\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\"\n        ]\n      },\n      {\n        \"id\": \"serde_json 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"itoa 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"ryu 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"itoa\",\n            \"pkg\": \"itoa 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"ryu\",\n            \"pkg\": \"ryu 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"serde\",\n            \"pkg\": \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"sha2 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"cpufeatures 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"block_buffer\",\n            \"pkg\": \"block-buffer 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"cpufeatures\",\n            \"pkg\": \"cpufeatures 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\"\n              }\n            ]\n          },\n          {\n            \"name\": \"digest\",\n            \"pkg\": \"digest 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"opaque_debug\",\n            \"pkg\": \"opaque-debug 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"slab 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"smallvec 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"socket2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(unix)\"\n              }\n            ]\n          },\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(windows)\"\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"all\"\n        ]\n      },\n      {\n        \"id\": \"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"spin 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"lock_api_crate\",\n            \"pkg\": \"lock_api 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"barrier\",\n          \"default\",\n          \"lazy\",\n          \"lock_api\",\n          \"lock_api_crate\",\n          \"mutex\",\n          \"once\",\n          \"rwlock\",\n          \"spin_mutex\"\n        ]\n      },\n      {\n        \"id\": \"sqlformat 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"itertools 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"nom 7.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"itertools\",\n            \"pkg\": \"itertools 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"nom\",\n            \"pkg\": \"nom 7.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"unicode_categories\",\n            \"pkg\": \"unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"sqlx 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"sqlx-core 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sqlx-macros 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"sqlx_core\",\n            \"pkg\": \"sqlx-core 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sqlx_macros\",\n            \"pkg\": \"sqlx-macros 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"_rt-tokio\",\n          \"default\",\n          \"macros\",\n          \"migrate\",\n          \"offline\",\n          \"runtime-tokio-rustls\",\n          \"sqlite\",\n          \"sqlx-macros\"\n        ]\n      },\n      {\n        \"id\": \"sqlx-core 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"ahash 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"atoi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"byteorder 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"bytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"crc 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"crossbeam-queue 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"flume 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-channel 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-executor 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-intrusive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"futures-util 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"hashlink 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"indexmap 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"itoa 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libsqlite3-sys 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"paste 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"rustls 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sha2 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"smallvec 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sqlformat 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sqlx-rt 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"thiserror 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"tokio-stream 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"url 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"webpki-roots 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"ahash\",\n            \"pkg\": \"ahash 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"atoi\",\n            \"pkg\": \"atoi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"bitflags\",\n            \"pkg\": \"bitflags 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"byteorder\",\n            \"pkg\": \"byteorder 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"bytes\",\n            \"pkg\": \"bytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"crc\",\n            \"pkg\": \"crc 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"crossbeam_queue\",\n            \"pkg\": \"crossbeam-queue 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"either\",\n            \"pkg\": \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"flume\",\n            \"pkg\": \"flume 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_channel\",\n            \"pkg\": \"futures-channel 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_executor\",\n            \"pkg\": \"futures-executor 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_intrusive\",\n            \"pkg\": \"futures-intrusive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"futures_util\",\n            \"pkg\": \"futures-util 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"hashlink\",\n            \"pkg\": \"hashlink 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"hex\",\n            \"pkg\": \"hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"indexmap\",\n            \"pkg\": \"indexmap 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"itoa\",\n            \"pkg\": \"itoa 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"libsqlite3_sys\",\n            \"pkg\": \"libsqlite3-sys 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"log\",\n            \"pkg\": \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"memchr\",\n            \"pkg\": \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"once_cell\",\n            \"pkg\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"paste\",\n            \"pkg\": \"paste 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"percent_encoding\",\n            \"pkg\": \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"rustls\",\n            \"pkg\": \"rustls 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"serde\",\n            \"pkg\": \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sha2\",\n            \"pkg\": \"sha2 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"smallvec\",\n            \"pkg\": \"smallvec 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sqlformat\",\n            \"pkg\": \"sqlformat 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sqlx_rt\",\n            \"pkg\": \"sqlx-rt 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"stringprep\",\n            \"pkg\": \"stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"thiserror\",\n            \"pkg\": \"thiserror 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"tokio_stream\",\n            \"pkg\": \"tokio-stream 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"url\",\n            \"pkg\": \"url 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"webpki\",\n            \"pkg\": \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"webpki_roots\",\n            \"pkg\": \"webpki-roots 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"_rt-tokio\",\n          \"_tls-rustls\",\n          \"crc\",\n          \"flume\",\n          \"futures-executor\",\n          \"libsqlite3-sys\",\n          \"migrate\",\n          \"offline\",\n          \"runtime-tokio-rustls\",\n          \"rustls\",\n          \"serde\",\n          \"sha2\",\n          \"sqlite\",\n          \"tokio-stream\",\n          \"webpki\",\n          \"webpki-roots\"\n        ]\n      },\n      {\n        \"id\": \"sqlx-macros 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"heck 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"serde_json 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sha2 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sqlx-core 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"sqlx-rt 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"url 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"dotenv\",\n            \"pkg\": \"dotenv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"either\",\n            \"pkg\": \"either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"heck\",\n            \"pkg\": \"heck 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"hex\",\n            \"pkg\": \"hex 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"once_cell\",\n            \"pkg\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"serde\",\n            \"pkg\": \"serde 1.0.136 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"serde_json\",\n            \"pkg\": \"serde_json 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sha2\",\n            \"pkg\": \"sha2 0.9.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sqlx_core\",\n            \"pkg\": \"sqlx-core 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"sqlx_rt\",\n            \"pkg\": \"sqlx-rt 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"syn\",\n            \"pkg\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"url\",\n            \"pkg\": \"url 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"_rt-tokio\",\n          \"hex\",\n          \"migrate\",\n          \"offline\",\n          \"runtime-tokio-rustls\",\n          \"serde\",\n          \"serde_json\",\n          \"sha2\",\n          \"sqlite\"\n        ]\n      },\n      {\n        \"id\": \"sqlx-rt 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"tokio-rustls 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"once_cell\",\n            \"pkg\": \"once_cell 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"tokio\",\n            \"pkg\": \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"tokio_rustls\",\n            \"pkg\": \"tokio-rustls 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"_rt-tokio\",\n          \"_tls-rustls\",\n          \"once_cell\",\n          \"runtime-tokio-rustls\",\n          \"tokio\",\n          \"tokio-rustls\"\n        ]\n      },\n      {\n        \"id\": \"stringprep 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"unicode-bidi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"unicode-normalization 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"unicode_bidi\",\n            \"pkg\": \"unicode-bidi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"unicode_normalization\",\n            \"pkg\": \"unicode-normalization 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"unicode-xid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"unicode_xid\",\n            \"pkg\": \"unicode-xid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"clone-impls\",\n          \"default\",\n          \"derive\",\n          \"full\",\n          \"parsing\",\n          \"printing\",\n          \"proc-macro\",\n          \"quote\",\n          \"visit\",\n          \"visit-mut\"\n        ]\n      },\n      {\n        \"id\": \"thiserror 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"thiserror-impl 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"thiserror_impl\",\n            \"pkg\": \"thiserror-impl 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"thiserror-impl 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"syn\",\n            \"pkg\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"tinyvec 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"tinyvec_macros\",\n            \"pkg\": \"tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"alloc\",\n          \"default\",\n          \"tinyvec_macros\"\n        ]\n      },\n      {\n        \"id\": \"tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"bytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"mio 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"num_cpus 1.13.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"socket2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"bytes\",\n            \"pkg\": \"bytes 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"libc\",\n            \"pkg\": \"libc 0.2.122 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(unix)\"\n              }\n            ]\n          },\n          {\n            \"name\": \"memchr\",\n            \"pkg\": \"memchr 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"mio\",\n            \"pkg\": \"mio 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"num_cpus\",\n            \"pkg\": \"num_cpus 1.13.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"pin_project_lite\",\n            \"pkg\": \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"socket2\",\n            \"pkg\": \"socket2 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"winapi\",\n            \"pkg\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"cfg(windows)\"\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"bytes\",\n          \"default\",\n          \"fs\",\n          \"io-util\",\n          \"libc\",\n          \"memchr\",\n          \"mio\",\n          \"net\",\n          \"num_cpus\",\n          \"rt\",\n          \"rt-multi-thread\",\n          \"socket2\",\n          \"sync\",\n          \"time\",\n          \"winapi\"\n        ]\n      },\n      {\n        \"id\": \"tokio-rustls 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"rustls 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"rustls\",\n            \"pkg\": \"rustls 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"tokio\",\n            \"pkg\": \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"webpki\",\n            \"pkg\": \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"tokio-stream 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"futures_core\",\n            \"pkg\": \"futures-core 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"pin_project_lite\",\n            \"pkg\": \"pin-project-lite 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"tokio\",\n            \"pkg\": \"tokio 1.17.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"fs\",\n          \"time\"\n        ]\n      },\n      {\n        \"id\": \"typenum 1.15.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"unicode-bidi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"unicode-normalization 0.1.19 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"tinyvec 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"tinyvec\",\n            \"pkg\": \"tinyvec 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"unicode-segmentation 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"unicode-xid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\"\n        ]\n      },\n      {\n        \"id\": \"unicode_categories 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"url 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"form_urlencoded 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"idna 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"form_urlencoded\",\n            \"pkg\": \"form_urlencoded 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"idna\",\n            \"pkg\": \"idna 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"matches\",\n            \"pkg\": \"matches 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"percent_encoding\",\n            \"pkg\": \"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"vcpkg 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"version_check 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"wasi 0.10.2+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"wasi 0.11.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": [\n          \"default\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"wasm-bindgen 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasm-bindgen-macro 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"cfg_if\",\n            \"pkg\": \"cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"wasm_bindgen_macro\",\n            \"pkg\": \"wasm-bindgen-macro 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"spans\",\n          \"std\"\n        ]\n      },\n      {\n        \"id\": \"wasm-bindgen-backend 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"bumpalo 3.9.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasm-bindgen-shared 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"bumpalo\",\n            \"pkg\": \"bumpalo 3.9.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"lazy_static\",\n            \"pkg\": \"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"log\",\n            \"pkg\": \"log 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"syn\",\n            \"pkg\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"wasm_bindgen_shared\",\n            \"pkg\": \"wasm-bindgen-shared 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"spans\"\n        ]\n      },\n      {\n        \"id\": \"wasm-bindgen-macro 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasm-bindgen-macro-support 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"wasm_bindgen_macro_support\",\n            \"pkg\": \"wasm-bindgen-macro-support 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"spans\"\n        ]\n      },\n      {\n        \"id\": \"wasm-bindgen-macro-support 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasm-bindgen-backend 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasm-bindgen-shared 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"proc_macro2\",\n            \"pkg\": \"proc-macro2 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"quote\",\n            \"pkg\": \"quote 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"syn\",\n            \"pkg\": \"syn 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"wasm_bindgen_backend\",\n            \"pkg\": \"wasm-bindgen-backend 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"wasm_bindgen_shared\",\n            \"pkg\": \"wasm-bindgen-shared 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"spans\"\n        ]\n      },\n      {\n        \"id\": \"wasm-bindgen-shared 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"web-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"js-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"wasm-bindgen 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"js_sys\",\n            \"pkg\": \"js-sys 0.3.57 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"wasm_bindgen\",\n            \"pkg\": \"wasm-bindgen 0.2.80 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"Crypto\",\n          \"EventTarget\",\n          \"Window\"\n        ]\n      },\n      {\n        \"id\": \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"ring\",\n            \"pkg\": \"ring 0.16.20 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          },\n          {\n            \"name\": \"untrusted\",\n            \"pkg\": \"untrusted 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"default\",\n          \"std\",\n          \"trust_anchor_util\"\n        ]\n      },\n      {\n        \"id\": \"webpki-roots 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"webpki\",\n            \"pkg\": \"webpki 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": null\n              }\n            ]\n          }\n        ],\n        \"features\": []\n      },\n      {\n        \"id\": \"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [\n          \"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n          \"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\"\n        ],\n        \"deps\": [\n          {\n            \"name\": \"winapi_i686_pc_windows_gnu\",\n            \"pkg\": \"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"i686-pc-windows-gnu\"\n              }\n            ]\n          },\n          {\n            \"name\": \"winapi_x86_64_pc_windows_gnu\",\n            \"pkg\": \"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n            \"dep_kinds\": [\n              {\n                \"kind\": null,\n                \"target\": \"x86_64-pc-windows-gnu\"\n              }\n            ]\n          }\n        ],\n        \"features\": [\n          \"cfg\",\n          \"errhandlingapi\",\n          \"evntrace\",\n          \"fileapi\",\n          \"handleapi\",\n          \"in6addr\",\n          \"inaddr\",\n          \"ioapiset\",\n          \"minwinbase\",\n          \"minwindef\",\n          \"mswsock\",\n          \"namedpipeapi\",\n          \"ntdef\",\n          \"ntsecapi\",\n          \"ntstatus\",\n          \"std\",\n          \"synchapi\",\n          \"winbase\",\n          \"windef\",\n          \"winerror\",\n          \"winioctl\",\n          \"winnt\",\n          \"winsock2\",\n          \"ws2def\",\n          \"ws2ipdef\",\n          \"ws2tcpip\",\n          \"wtypesbase\"\n        ]\n      },\n      {\n        \"id\": \"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      },\n      {\n        \"id\": \"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)\",\n        \"dependencies\": [],\n        \"deps\": [],\n        \"features\": []\n      }\n    ],\n    \"root\": \"b_in_workspace_lib 0.1.0 (path+file:///home/user/problematic/workspace/b_in_workspace_lib)\"\n  },\n  \"target_directory\": \"/home/user/problematic/workspace/target\",\n  \"version\": 1,\n  \"workspace_root\": \"/home/user/problematic/workspace\",\n  \"metadata\": null\n}\n"
  },
  {
    "path": "sqlx-cli/tests/common/mod.rs",
    "content": "use assert_cmd::{assert::Assert, Command};\n\nuse sqlx::_unstable::config::Config;\nuse sqlx::{migrate::Migrate, Connection, SqliteConnection};\nuse std::{\n    env, fs,\n    path::{Path, PathBuf},\n};\n\npub struct TestDatabase {\n    file_path: PathBuf,\n    migrations_path: PathBuf,\n    pub config_path: Option<PathBuf>,\n}\n\nimpl TestDatabase {\n    pub fn new(name: &str, migrations: &str) -> Self {\n        // Note: only set when _building_\n        let temp_dir = option_env!(\"CARGO_TARGET_TMPDIR\").map_or_else(env::temp_dir, PathBuf::from);\n\n        let test_dir = temp_dir.join(\"migrate\");\n\n        fs::create_dir_all(&test_dir)\n            .unwrap_or_else(|e| panic!(\"error creating directory: {test_dir:?}: {e}\"));\n\n        let file_path = test_dir.join(format!(\"test-{name}.db\"));\n\n        if file_path.exists() {\n            fs::remove_file(&file_path)\n                .unwrap_or_else(|e| panic!(\"error deleting test database {file_path:?}: {e}\"));\n        }\n\n        let this = Self {\n            file_path,\n            migrations_path: Path::new(\"tests\").join(migrations),\n            config_path: None,\n        };\n\n        Command::cargo_bin(\"cargo-sqlx\")\n            .unwrap()\n            .args([\n                \"sqlx\",\n                \"database\",\n                \"create\",\n                \"--database-url\",\n                &this.connection_string(),\n            ])\n            .assert()\n            .success();\n        this\n    }\n\n    pub fn set_migrations(&mut self, migrations: &str) {\n        self.migrations_path = Path::new(\"tests\").join(migrations);\n    }\n\n    pub fn connection_string(&self) -> String {\n        format!(\"sqlite://{}\", self.file_path.display())\n    }\n\n    pub fn run_migration(&self, revert: bool, version: Option<i64>, dry_run: bool) -> Assert {\n        let mut command = Command::cargo_bin(\"sqlx\").unwrap();\n        command\n            .args([\n                \"migrate\",\n                match revert {\n                    true => \"revert\",\n                    false => \"run\",\n                },\n                \"--database-url\",\n                &self.connection_string(),\n                \"--source\",\n            ])\n            .arg(&self.migrations_path);\n\n        if let Some(config_path) = &self.config_path {\n            command.arg(\"--config\").arg(config_path);\n        }\n\n        if let Some(version) = version {\n            command.arg(\"--target-version\").arg(version.to_string());\n        }\n\n        if dry_run {\n            command.arg(\"--dry-run\");\n        }\n\n        command.assert()\n    }\n\n    pub async fn applied_migrations(&self) -> Vec<i64> {\n        let mut conn = SqliteConnection::connect(&self.connection_string())\n            .await\n            .unwrap();\n\n        let config = Config::default();\n\n        conn.list_applied_migrations(config.migrate.table_name())\n            .await\n            .unwrap()\n            .iter()\n            .map(|m| m.version)\n            .collect()\n    }\n\n    pub fn migrate_info(&self) -> Assert {\n        let mut command = Command::cargo_bin(\"sqlx\").unwrap();\n        command\n            .args([\n                \"migrate\",\n                \"info\",\n                \"--database-url\",\n                &self.connection_string(),\n                \"--source\",\n            ])\n            .arg(&self.migrations_path);\n\n        if let Some(config_path) = &self.config_path {\n            command.arg(\"--config\").arg(config_path);\n        }\n\n        command.assert()\n    }\n}\n\nimpl Drop for TestDatabase {\n    fn drop(&mut self) {\n        // Only remove the database if there isn't a failure.\n        if !std::thread::panicking() {\n            fs::remove_file(&self.file_path).unwrap_or_else(|e| {\n                panic!(\"error deleting test database {:?}: {e}\", self.file_path)\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/BOM/.gitattributes",
    "content": "*.sql text eol=lf\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/BOM/1_user.sql",
    "content": "﻿create table user\n(\n    -- integer primary keys are the most efficient in SQLite\n    user_id  integer primary key,\n    username text unique not null\n);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/BOM/2_post.sql",
    "content": "﻿create table post\n(\n    post_id    integer primary key,\n    user_id    integer not null references user (user_id),\n    content    text    not null,\n    -- Defaults have to be wrapped in parenthesis\n    created_at datetime default (datetime('now'))\n);\n\ncreate index post_created_at on post (created_at desc);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/BOM/3_comment.sql",
    "content": "﻿create table comment\n(\n    comment_id integer primary key,\n    post_id    integer not null references post (post_id),\n    user_id    integer not null references \"user\" (user_id),\n    content    text    not null,\n    created_at datetime default (datetime('now'))\n);\n\ncreate index comment_created_at on comment (created_at desc);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/CRLF/.gitattributes",
    "content": "*.sql text eol=crlf\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/CRLF/1_user.sql",
    "content": "create table user\r\n(\r\n    -- integer primary keys are the most efficient in SQLite\r\n    user_id  integer primary key,\r\n    username text unique not null\r\n);\r\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/CRLF/2_post.sql",
    "content": "create table post\r\n(\r\n    post_id    integer primary key,\r\n    user_id    integer not null references user (user_id),\r\n    content    text    not null,\r\n    -- Defaults have to be wrapped in parenthesis\r\n    created_at datetime default (datetime('now'))\r\n);\r\n\r\ncreate index post_created_at on post (created_at desc);\r\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/CRLF/3_comment.sql",
    "content": "create table comment\r\n(\r\n    comment_id integer primary key,\r\n    post_id    integer not null references post (post_id),\r\n    user_id    integer not null references \"user\" (user_id),\r\n    content    text    not null,\r\n    created_at datetime default (datetime('now'))\r\n);\r\n\r\ncreate index comment_created_at on comment (created_at desc);\r\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/LF/.gitattributes",
    "content": "*.sql text eol=lf\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/LF/1_user.sql",
    "content": "create table user\n(\n    -- integer primary keys are the most efficient in SQLite\n    user_id  integer primary key,\n    username text unique not null\n);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/LF/2_post.sql",
    "content": "create table post\n(\n    post_id    integer primary key,\n    user_id    integer not null references user (user_id),\n    content    text    not null,\n    -- Defaults have to be wrapped in parenthesis\n    created_at datetime default (datetime('now'))\n);\n\ncreate index post_created_at on post (created_at desc);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/LF/3_comment.sql",
    "content": "create table comment\n(\n    comment_id integer primary key,\n    post_id    integer not null references post (post_id),\n    user_id    integer not null references \"user\" (user_id),\n    content    text    not null,\n    created_at datetime default (datetime('now'))\n);\n\ncreate index comment_created_at on comment (created_at desc);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/oops-all-tabs/.gitattributes",
    "content": "*.sql text eol=lf\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/oops-all-tabs/1_user.sql",
    "content": "create table user\n(\n\t-- integer primary keys are the most efficient in SQLite\n\tuser_id  integer primary key,\n\tusername text unique not null\n);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/oops-all-tabs/2_post.sql",
    "content": "create table post\n(\n\tpost_id\tinteger primary key,\n\tuser_id\tinteger not null references user (user_id),\n\tcontent\ttext\tnot null,\n\t-- Defaults have to be wrapped in parenthesis\n\tcreated_at datetime default (datetime('now'))\n);\n\ncreate index post_created_at on post (created_at desc);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/oops-all-tabs/3_comment.sql",
    "content": "create table comment\n(\n\tcomment_id integer primary key,\n\tpost_id\tinteger not null references post (post_id),\n\tuser_id\tinteger not null references \"user\" (user_id),\n\tcontent\ttext\tnot null,\n\tcreated_at datetime default (datetime('now'))\n);\n\ncreate index comment_created_at on comment (created_at desc);\n"
  },
  {
    "path": "sqlx-cli/tests/ignored-chars/sqlx.toml",
    "content": "[migrate]\n# Ignore common whitespace characters (beware syntactically significant whitespace!)\n# Space, tab, CR, LF, zero-width non-breaking space (U+FEFF)\n#\n# U+FEFF is added by some editors as a magic number at the beginning of a text file indicating it is UTF-8 encoded,\n# where it is known as a byte-order mark (BOM): https://en.wikipedia.org/wiki/Byte_order_mark\nignored-chars = [\" \", \"\\t\", \"\\r\", \"\\n\", \"\\uFEFF\"]\n"
  },
  {
    "path": "sqlx-cli/tests/migrate.rs",
    "content": "mod common;\n\nuse common::TestDatabase;\n\n#[tokio::test]\nasync fn run_reversible_migrations() {\n    let all_migrations: Vec<i64> = vec![\n        20230101000000,\n        20230201000000,\n        20230301000000,\n        20230401000000,\n        20230501000000,\n    ];\n    // Without --target-version specified.k\n    {\n        let db = TestDatabase::new(\"run_reversible_latest\", \"migrations_reversible\");\n        db.run_migration(false, None, false).success();\n        assert_eq!(db.applied_migrations().await, all_migrations);\n    }\n    // With --target-version specified.\n    {\n        let db = TestDatabase::new(\"run_reversible_latest_explicit\", \"migrations_reversible\");\n\n        // Move to latest, explicitly specified.\n        db.run_migration(false, Some(20230501000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, all_migrations);\n\n        // Move to latest when we're already at the latest.\n        db.run_migration(false, Some(20230501000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, all_migrations);\n\n        // Upgrade to an old version.\n        db.run_migration(false, Some(20230301000000), false)\n            .failure();\n        assert_eq!(db.applied_migrations().await, all_migrations);\n    }\n    // With --target-version, incrementally upgrade.\n    {\n        let db = TestDatabase::new(\"run_reversible_incremental\", \"migrations_reversible\");\n\n        // First version\n        db.run_migration(false, Some(20230101000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, vec![20230101000000]);\n\n        // Dry run upgrade to latest.\n        db.run_migration(false, None, true).success();\n        assert_eq!(db.applied_migrations().await, vec![20230101000000]);\n\n        // Dry run upgrade + 2\n        db.run_migration(false, Some(20230301000000), true)\n            .success();\n        assert_eq!(db.applied_migrations().await, vec![20230101000000]);\n\n        // Upgrade to non-existent version.\n        db.run_migration(false, Some(20230901000000999), false)\n            .failure();\n        assert_eq!(db.applied_migrations().await, vec![20230101000000]);\n\n        // Upgrade + 1\n        db.run_migration(false, Some(20230201000000), false)\n            .success();\n        assert_eq!(\n            db.applied_migrations().await,\n            vec![20230101000000, 20230201000000]\n        );\n\n        // Upgrade + 2\n        db.run_migration(false, Some(20230401000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, all_migrations[..4]);\n    }\n}\n\n#[tokio::test]\nasync fn revert_migrations() {\n    let all_migrations: Vec<i64> = vec![\n        20230101000000,\n        20230201000000,\n        20230301000000,\n        20230401000000,\n        20230501000000,\n    ];\n\n    // Without --target-version\n    {\n        let db = TestDatabase::new(\"revert_incremental\", \"migrations_reversible\");\n        db.run_migration(false, None, false).success();\n\n        // Dry-run\n        db.run_migration(true, None, true).success();\n        assert_eq!(db.applied_migrations().await, all_migrations);\n\n        // Downgrade one\n        db.run_migration(true, None, false).success();\n        assert_eq!(db.applied_migrations().await, all_migrations[..4]);\n\n        // Downgrade one\n        db.run_migration(true, None, false).success();\n        assert_eq!(db.applied_migrations().await, all_migrations[..3]);\n    }\n    // With --target-version\n    {\n        let db = TestDatabase::new(\"revert_incremental\", \"migrations_reversible\");\n        db.run_migration(false, None, false).success();\n\n        // Dry-run downgrade to version 3.\n        db.run_migration(true, Some(20230301000000), true).success();\n        assert_eq!(db.applied_migrations().await, all_migrations);\n\n        // Downgrade to version 3.\n        db.run_migration(true, Some(20230301000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, all_migrations[..3]);\n\n        // Try downgrading to the same version.\n        db.run_migration(true, Some(20230301000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, all_migrations[..3]);\n\n        // Try downgrading to a newer version.\n        db.run_migration(true, Some(20230401000000), false)\n            .failure();\n        assert_eq!(db.applied_migrations().await, all_migrations[..3]);\n\n        // Try downgrading to a non-existent version.\n        db.run_migration(true, Some(9999), false).failure();\n        assert_eq!(db.applied_migrations().await, all_migrations[..3]);\n\n        // Ensure we can still upgrade\n        db.run_migration(false, Some(20230401000000), false)\n            .success();\n        assert_eq!(db.applied_migrations().await, all_migrations[..4]);\n\n        // Downgrade to zero.\n        db.run_migration(true, Some(0), false).success();\n        assert_eq!(db.applied_migrations().await, Vec::<i64>::new());\n    }\n}\n\n#[tokio::test]\nasync fn ignored_chars() {\n    let mut db = TestDatabase::new(\"ignored-chars\", \"ignored-chars/LF\");\n    db.config_path = Some(\"tests/ignored-chars/sqlx.toml\".into());\n\n    db.run_migration(false, None, false).success();\n\n    db.set_migrations(\"ignored-chars/CRLF\");\n\n    let expected_info = \"1/installed user\\n2/installed post\\n3/installed comment\\n\";\n\n    // `ignored-chars` should produce the same migration checksum here\n    db.migrate_info().success().stdout(expected_info);\n\n    // Running migration should be a no-op\n    db.run_migration(false, None, false).success().stdout(\"\");\n\n    db.set_migrations(\"ignored-chars/BOM\");\n    db.migrate_info().success().stdout(expected_info);\n    db.run_migration(false, None, false).success().stdout(\"\");\n\n    db.set_migrations(\"ignored-chars/oops-all-tabs\");\n    db.migrate_info().success().stdout(expected_info);\n    db.run_migration(false, None, false).success().stdout(\"\");\n}\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230101000000_test1.down.sql",
    "content": "DROP TABLE test1;\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230101000000_test1.up.sql",
    "content": "CREATE TABLE test1(x INTEGER PRIMARY KEY);\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230201000000_test2.down.sql",
    "content": "DROP TABLE test2;\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230201000000_test2.up.sql",
    "content": "CREATE TABLE test2(x INTEGER PRIMARY KEY);\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230301000000_test3.down.sql",
    "content": "DROP TABLE test3;\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230301000000_test3.up.sql",
    "content": "CREATE TABLE test3(x INTEGER PRIMARY KEY);\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230401000000_test4.down.sql",
    "content": "DROP TABLE test4;\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230401000000_test4.up.sql",
    "content": "CREATE TABLE test4(x INTEGER PRIMARY KEY);\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230501000000_test5.down.sql",
    "content": "DROP TABLE test5;\n"
  },
  {
    "path": "sqlx-cli/tests/migrations_reversible/20230501000000_test5.up.sql",
    "content": "CREATE TABLE test5(x INTEGER PRIMARY KEY);\n"
  },
  {
    "path": "sqlx-core/Cargo.toml",
    "content": "[package]\nname = \"sqlx-core\"\ndescription = \"Core of SQLx, the rust SQL toolkit. Not intended to be used directly.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n[package.metadata.docs.rs]\nfeatures = [\"offline\"]\n\n[features]\ndefault = []\nmigrate = [\"sha2\", \"crc\"]\n\nany = []\n\njson = [\"serde\", \"serde_json\"]\n\n# for conditional compilation\n_rt-async-global-executor = [\"async-global-executor\", \"_rt-async-io\", \"_rt-async-task\"]\n_rt-async-io = [\"async-io\", \"async-fs\"] # see note at async-fs declaration\n_rt-async-std = [\"async-std\", \"_rt-async-io\"]\n_rt-async-task = [\"async-task\"]\n_rt-smol = [\"smol\", \"_rt-async-io\", \"_rt-async-task\"]\n_rt-tokio = [\"tokio\", \"tokio-stream\"]\n\n_tls-native-tls = [\"native-tls\"]\n_tls-rustls-aws-lc-rs = [\"_tls-rustls\", \"rustls/aws-lc-rs\", \"webpki-roots\"]\n_tls-rustls-ring-webpki = [\"_tls-rustls\", \"rustls/ring\", \"webpki-roots\"]\n_tls-rustls-ring-native-roots = [\"_tls-rustls\", \"rustls/ring\", \"rustls-native-certs\"]\n_tls-rustls = [\"rustls\"]\n_tls-none = []\n\n# support offline/decoupled building (enables serialization of `Describe`)\noffline = [\"serde\", \"either/serde\"]\n\n# Enable parsing of `sqlx.toml`.\n# For simplicity, the `config` module is always enabled,\n# but disabling this disables the `serde` derives and the `toml` crate,\n# which is a good bit less code to compile if the feature isn't being used.\nsqlx-toml = [\"serde\", \"toml/parse\"]\n\n_unstable-doc = [\"sqlx-toml\"]\n\n[dependencies]\n# Runtimes\nasync-global-executor = { workspace = true, optional = true }\nasync-std = { workspace = true, optional = true }\nsmol = { workspace = true, optional = true }\ntokio = { workspace = true, optional = true }\n\n# TLS\nnative-tls = { version = \"0.2.10\", optional = true }\n\nrustls = { version = \"0.23.24\", default-features = false, features = [\"std\", \"tls12\"], optional = true }\nwebpki-roots = { version = \"1\", optional = true }\nrustls-native-certs = { version = \"0.8.0\", optional = true }\n\n# Type Integrations\nbit-vec = { workspace = true, optional = true }\nbigdecimal = { workspace = true, optional = true }\nchrono = { workspace = true, optional = true }\nrust_decimal = { workspace = true, optional = true }\ntime = { workspace = true, optional = true }\nipnet = { workspace = true, optional = true }\nipnetwork = { workspace = true, optional = true }\nmac_address = { workspace = true, optional = true }\nuuid = { workspace = true, optional = true }\n\n# work around bug in async-fs 2.0.0, which references futures-lite dependency wrongly, see https://github.com/launchbadge/sqlx/pull/3791#issuecomment-3043363281\nasync-fs = { version = \"2.1\", optional = true }\nasync-io = { version = \"2.4.1\", optional = true }\nasync-task = { version = \"4.7.1\", optional = true }\n\nbase64 = { version = \"0.22.0\", default-features = false, features = [\"std\"] }\nbytes = \"1.1.0\"\ncfg-if = { workspace = true }\ncrc = { version = \"3\", optional = true }\ncrossbeam-queue = \"0.3.2\"\neither = \"1.6.1\"\nfutures-core = { version = \"0.3.19\", default-features = false }\nfutures-io = \"0.3.24\"\nfutures-intrusive = \"0.5.0\"\nfutures-util = { version = \"0.3.19\", default-features = false, features = [\"alloc\", \"sink\", \"io\"] }\nlog = { version = \"0.4.18\", default-features = false }\nmemchr = { version = \"2.4.1\", default-features = false }\npercent-encoding = \"2.1.0\"\nserde = { version = \"1.0.132\", features = [\"derive\", \"rc\"], optional = true }\nserde_json = { version = \"1.0.73\", features = [\"raw_value\"], optional = true }\ntoml = { version = \"0.8.16\", optional = true }\nsha2 = { version = \"0.10.0\", default-features = false, optional = true }\n#sqlformat = \"0.2.0\"\ntokio-stream = { version = \"0.1.8\", features = [\"fs\"], optional = true }\ntracing = { version = \"0.1.37\", features = [\"log\"] }\nsmallvec = \"1.7.0\"\nurl = { version = \"2.2.2\" }\nbstr = { version = \"1.0\", default-features = false, features = [\"std\"], optional = true }\nhashlink = \"0.11.0\"\nindexmap = \"2.0\"\nevent-listener = \"5.2.0\"\nhashbrown = \"0.16.0\"\n\nthiserror.workspace = true\n\n[dev-dependencies]\ntokio = { version = \"1\", features = [\"rt\"] }\n\n[dev-dependencies.sqlx]\n# FIXME: https://github.com/rust-lang/cargo/issues/15622\n# workspace = true\npath = \"..\"\ndefault-features = false\nfeatures = [\"postgres\", \"sqlite\", \"mysql\", \"migrate\", \"macros\", \"time\", \"uuid\"]\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "sqlx-core/src/acquire.rs",
    "content": "use crate::database::Database;\nuse crate::error::Error;\nuse crate::pool::{MaybePoolConnection, Pool, PoolConnection};\n\nuse crate::transaction::Transaction;\nuse futures_core::future::BoxFuture;\nuse std::ops::{Deref, DerefMut};\n\n/// Acquire connections or transactions from a database in a generic way.\n///\n/// If you want to accept generic database connections that implement\n/// [`Acquire`] which then allows you to [`acquire`][`Acquire::acquire`] a\n/// connection or [`begin`][`Acquire::begin`] a transaction, then you can do it\n/// like that:\n///\n/// ```rust,ignore\n/// # use sqlx::{Acquire, postgres::Postgres, error::BoxDynError};\n/// async fn run_query<'a, A>(conn: A) -> Result<(), BoxDynError>\n/// where\n///     A: Acquire<'a, Database = Postgres>,\n/// {\n///     let mut conn = conn.acquire().await?;\n///\n///     sqlx::query!(\"SELECT 1 as v\").fetch_one(&mut *conn).await?;\n///     sqlx::query!(\"SELECT 2 as v\").fetch_one(&mut *conn).await?;\n///\n///     Ok(())\n/// }\n/// ```\n///\n/// If you run into a lifetime error about \"implementation of `sqlx::Acquire` is\n/// not general enough\", the [workaround] looks like this:\n///\n/// ```rust,ignore\n/// # use std::future::Future;\n/// # use sqlx::{Acquire, postgres::Postgres, error::BoxDynError};\n/// fn run_query<'a, 'c, A>(conn: A) -> impl Future<Output = Result<(), BoxDynError>> + Send + 'a\n/// where\n///     A: Acquire<'c, Database = Postgres> + Send + 'a,\n/// {\n///     async move {\n///         let mut conn = conn.acquire().await?;\n///\n///         sqlx::query!(\"SELECT 1 as v\").fetch_one(&mut *conn).await?;\n///         sqlx::query!(\"SELECT 2 as v\").fetch_one(&mut *conn).await?;\n///\n///         Ok(())\n///     }\n/// }\n/// ```\n///\n/// However, if you really just want to accept both, a transaction or a\n/// connection as an argument to a function, then it's easier to just accept a\n/// mutable reference to a database connection like so:\n///\n/// ```rust,ignore\n/// # use sqlx::{postgres::PgConnection, error::BoxDynError};\n/// async fn run_query(conn: &mut PgConnection) -> Result<(), BoxDynError> {\n///     sqlx::query!(\"SELECT 1 as v\").fetch_one(&mut *conn).await?;\n///     sqlx::query!(\"SELECT 2 as v\").fetch_one(&mut *conn).await?;\n///\n///     Ok(())\n/// }\n/// ```\n///\n/// The downside of this approach is that you have to `acquire` a connection\n/// from a pool first and can't directly pass the pool as argument.\n///\n/// [workaround]: https://github.com/launchbadge/sqlx/issues/1015#issuecomment-767787777\npub trait Acquire<'c> {\n    type Database: Database;\n\n    type Connection: Deref<Target = <Self::Database as Database>::Connection> + DerefMut + Send;\n\n    fn acquire(self) -> BoxFuture<'c, Result<Self::Connection, Error>>;\n\n    fn begin(self) -> BoxFuture<'c, Result<Transaction<'c, Self::Database>, Error>>;\n}\n\nimpl<'a, DB: Database> Acquire<'a> for &'_ Pool<DB> {\n    type Database = DB;\n\n    type Connection = PoolConnection<DB>;\n\n    fn acquire(self) -> BoxFuture<'static, Result<Self::Connection, Error>> {\n        Box::pin(self.acquire())\n    }\n\n    fn begin(self) -> BoxFuture<'static, Result<Transaction<'a, DB>, Error>> {\n        let conn = self.acquire();\n\n        Box::pin(async move {\n            Transaction::begin(MaybePoolConnection::PoolConnection(conn.await?), None).await\n        })\n    }\n}\n\n#[macro_export]\nmacro_rules! impl_acquire {\n    ($DB:ident, $C:ident) => {\n        impl<'c> $crate::acquire::Acquire<'c> for &'c mut $C {\n            type Database = $DB;\n\n            type Connection = &'c mut <$DB as $crate::database::Database>::Connection;\n\n            #[inline]\n            fn acquire(\n                self,\n            ) -> futures_core::future::BoxFuture<'c, Result<Self::Connection, $crate::error::Error>>\n            {\n                Box::pin(std::future::ready(Ok(self)))\n            }\n\n            #[inline]\n            fn begin(\n                self,\n            ) -> futures_core::future::BoxFuture<\n                'c,\n                Result<$crate::transaction::Transaction<'c, $DB>, $crate::error::Error>,\n            > {\n                $crate::transaction::Transaction::begin(self, None)\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "sqlx-core/src/any/arguments.rs",
    "content": "use crate::any::value::AnyValueKind;\nuse crate::any::{Any, AnyTypeInfoKind};\nuse crate::arguments::Arguments;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse std::sync::Arc;\n\n#[derive(Default)]\npub struct AnyArguments {\n    #[doc(hidden)]\n    pub values: AnyArgumentBuffer,\n}\n\nimpl Arguments for AnyArguments {\n    type Database = Any;\n\n    fn reserve(&mut self, additional: usize, _size: usize) {\n        self.values.0.reserve(additional);\n    }\n\n    fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'t, Self::Database> + Type<Self::Database>,\n    {\n        let _: IsNull = value.encode(&mut self.values)?;\n        Ok(())\n    }\n\n    fn len(&self) -> usize {\n        self.values.0.len()\n    }\n}\n\n#[derive(Default)]\npub struct AnyArgumentBuffer(#[doc(hidden)] pub Vec<AnyValueKind>);\n\nimpl AnyArguments {\n    #[doc(hidden)]\n    pub fn convert_into<'a, A: Arguments>(self) -> Result<A, BoxDynError>\n    where\n        Option<i32>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<bool>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<i16>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<i32>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<i64>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<f32>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<f64>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<String>: Type<A::Database> + Encode<'a, A::Database>,\n        Option<Vec<u8>>: Type<A::Database> + Encode<'a, A::Database>,\n        bool: Type<A::Database> + Encode<'a, A::Database>,\n        i16: Type<A::Database> + Encode<'a, A::Database>,\n        i32: Type<A::Database> + Encode<'a, A::Database>,\n        i64: Type<A::Database> + Encode<'a, A::Database>,\n        f32: Type<A::Database> + Encode<'a, A::Database>,\n        f64: Type<A::Database> + Encode<'a, A::Database>,\n        Arc<String>: Type<A::Database> + Encode<'a, A::Database>,\n        Arc<str>: Type<A::Database> + Encode<'a, A::Database>,\n        Arc<Vec<u8>>: Type<A::Database> + Encode<'a, A::Database>,\n    {\n        let mut out = A::default();\n\n        for arg in self.values.0 {\n            match arg {\n                AnyValueKind::Null(AnyTypeInfoKind::Null) => out.add(Option::<i32>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::Bool) => out.add(Option::<bool>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::SmallInt) => out.add(Option::<i16>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::Integer) => out.add(Option::<i32>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::BigInt) => out.add(Option::<i64>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::Real) => out.add(Option::<f64>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::Double) => out.add(Option::<f32>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::Text) => out.add(Option::<String>::None),\n                AnyValueKind::Null(AnyTypeInfoKind::Blob) => out.add(Option::<Vec<u8>>::None),\n                AnyValueKind::Bool(b) => out.add(b),\n                AnyValueKind::SmallInt(i) => out.add(i),\n                AnyValueKind::Integer(i) => out.add(i),\n                AnyValueKind::BigInt(i) => out.add(i),\n                AnyValueKind::Real(r) => out.add(r),\n                AnyValueKind::Double(d) => out.add(d),\n                AnyValueKind::Text(t) => out.add(t),\n                AnyValueKind::TextSlice(t) => out.add(t),\n                AnyValueKind::Blob(b) => out.add(b),\n            }?\n        }\n        Ok(out)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/column.rs",
    "content": "use crate::any::{Any, AnyTypeInfo};\nuse crate::column::Column;\nuse crate::ext::ustr::UStr;\n\n#[derive(Debug, Clone)]\npub struct AnyColumn {\n    // NOTE: these fields are semver-exempt. See crate root docs for details.\n    #[doc(hidden)]\n    pub ordinal: usize,\n\n    #[doc(hidden)]\n    pub name: UStr,\n\n    #[doc(hidden)]\n    pub type_info: AnyTypeInfo,\n}\nimpl Column for AnyColumn {\n    type Database = Any;\n\n    fn ordinal(&self) -> usize {\n        self.ordinal\n    }\n\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn type_info(&self) -> &AnyTypeInfo {\n        &self.type_info\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/connection/backend.rs",
    "content": "use crate::any::{AnyArguments, AnyQueryResult, AnyRow, AnyStatement, AnyTypeInfo};\nuse crate::sql_str::SqlStr;\nuse either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse std::fmt::Debug;\n\npub trait AnyConnectionBackend: std::any::Any + Debug + Send + 'static {\n    /// The backend name.\n    fn name(&self) -> &str;\n\n    /// Explicitly close this database connection.\n    ///\n    /// This method is **not required** for safe and consistent operation. However, it is\n    /// recommended to call it instead of letting a connection `drop` as the database backend\n    /// will be faster at cleaning up resources.\n    fn close(self: Box<Self>) -> BoxFuture<'static, crate::Result<()>>;\n\n    /// Immediately close the connection without sending a graceful shutdown.\n    ///\n    /// This should still at least send a TCP `FIN` frame to let the server know we're dying.\n    #[doc(hidden)]\n    fn close_hard(self: Box<Self>) -> BoxFuture<'static, crate::Result<()>>;\n\n    /// Checks if a connection to the database is still valid.\n    fn ping(&mut self) -> BoxFuture<'_, crate::Result<()>>;\n\n    /// Begin a new transaction or establish a savepoint within the active transaction.\n    ///\n    /// If this is a new transaction, `statement` may be used instead of the\n    /// default \"BEGIN\" statement.\n    ///\n    /// If we are already inside a transaction and `statement.is_some()`, then\n    /// `Error::InvalidSavePoint` is returned without running any statements.\n    fn begin(&mut self, statement: Option<SqlStr>) -> BoxFuture<'_, crate::Result<()>>;\n\n    fn commit(&mut self) -> BoxFuture<'_, crate::Result<()>>;\n\n    fn rollback(&mut self) -> BoxFuture<'_, crate::Result<()>>;\n\n    fn start_rollback(&mut self);\n\n    /// Returns the current transaction depth.\n    ///\n    /// Transaction depth indicates the level of nested transactions:\n    /// - Level 0: No active transaction.\n    /// - Level 1: A transaction is active.\n    /// - Level 2 or higher: A transaction is active and one or more SAVEPOINTs have been created within it.\n    fn get_transaction_depth(&self) -> usize {\n        unimplemented!(\"get_transaction_depth() is not implemented for this backend. This is a provided method to avoid a breaking change, but it will become a required method in version 0.9 and later.\");\n    }\n\n    /// Checks if the connection is currently in a transaction.\n    ///\n    /// This method returns `true` if the current transaction depth is greater than 0,\n    /// indicating that a transaction is active. It returns `false` if the transaction depth is 0,\n    /// meaning no transaction is active.\n    #[inline]\n    fn is_in_transaction(&self) -> bool {\n        self.get_transaction_depth() != 0\n    }\n\n    /// The number of statements currently cached in the connection.\n    fn cached_statements_size(&self) -> usize {\n        0\n    }\n\n    /// Removes all statements from the cache, closing them on the server if\n    /// needed.\n    fn clear_cached_statements(&mut self) -> BoxFuture<'_, crate::Result<()>> {\n        Box::pin(async move { Ok(()) })\n    }\n\n    /// Forward to [`Connection::shrink_buffers()`].\n    ///\n    /// [`Connection::shrink_buffers()`]: method@crate::connection::Connection::shrink_buffers\n    fn shrink_buffers(&mut self);\n\n    #[doc(hidden)]\n    fn flush(&mut self) -> BoxFuture<'_, crate::Result<()>>;\n\n    #[doc(hidden)]\n    fn should_flush(&self) -> bool;\n\n    #[cfg(feature = \"migrate\")]\n    fn as_migrate(&mut self) -> crate::Result<&mut (dyn crate::migrate::Migrate + Send + 'static)> {\n        Err(crate::Error::Configuration(\n            format!(\n                \"{} driver does not support migrations or `migrate` feature was not enabled\",\n                self.name()\n            )\n            .into(),\n        ))\n    }\n\n    fn fetch_many(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxStream<'_, crate::Result<Either<AnyQueryResult, AnyRow>>>;\n\n    fn fetch_optional(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxFuture<'_, crate::Result<Option<AnyRow>>>;\n\n    fn prepare_with<'c, 'q: 'c>(\n        &'c mut self,\n        sql: SqlStr,\n        parameters: &[AnyTypeInfo],\n    ) -> BoxFuture<'c, crate::Result<AnyStatement>>;\n\n    #[cfg(feature = \"offline\")]\n    fn describe(\n        &mut self,\n        sql: SqlStr,\n    ) -> BoxFuture<'_, crate::Result<crate::describe::Describe<crate::any::Any>>>;\n}\n"
  },
  {
    "path": "sqlx-core/src/any/connection/executor.rs",
    "content": "use crate::any::{Any, AnyConnection, AnyQueryResult, AnyRow, AnyStatement, AnyTypeInfo};\nuse crate::error::Error;\nuse crate::executor::{Execute, Executor};\nuse crate::sql_str::SqlStr;\nuse either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::{stream, FutureExt, StreamExt};\nuse std::future;\n\nimpl<'c> Executor<'c> for &'c mut AnyConnection {\n    type Database = Any;\n\n    fn fetch_many<'e, 'q: 'e, E>(\n        self,\n        mut query: E,\n    ) -> BoxStream<'e, Result<Either<AnyQueryResult, AnyRow>, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Any>,\n    {\n        let arguments = match query.take_arguments().map_err(Error::Encode) {\n            Ok(arguments) => arguments,\n            Err(error) => return stream::once(future::ready(Err(error))).boxed(),\n        };\n        let persistent = query.persistent();\n        self.backend.fetch_many(query.sql(), persistent, arguments)\n    }\n\n    fn fetch_optional<'e, 'q: 'e, E>(\n        self,\n        mut query: E,\n    ) -> BoxFuture<'e, Result<Option<AnyRow>, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        let arguments = match query.take_arguments().map_err(Error::Encode) {\n            Ok(arguments) => arguments,\n            Err(error) => return future::ready(Err(error)).boxed(),\n        };\n        let persistent = query.persistent();\n        self.backend\n            .fetch_optional(query.sql(), persistent, arguments)\n    }\n\n    fn prepare_with<'e>(\n        self,\n        sql: SqlStr,\n        parameters: &[AnyTypeInfo],\n    ) -> BoxFuture<'e, Result<AnyStatement, Error>>\n    where\n        'c: 'e,\n    {\n        self.backend.prepare_with(sql, parameters)\n    }\n\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        sql: SqlStr,\n    ) -> BoxFuture<'e, Result<crate::describe::Describe<Self::Database>, Error>>\n    where\n        'c: 'e,\n    {\n        self.backend.describe(sql)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/connection/mod.rs",
    "content": "use futures_core::future::BoxFuture;\nuse std::future::Future;\n\nuse crate::any::{Any, AnyConnectOptions};\nuse crate::connection::{ConnectOptions, Connection};\nuse crate::error::Error;\n\nuse crate::config;\nuse crate::database::Database;\nuse crate::sql_str::SqlSafeStr;\nuse crate::transaction::Transaction;\npub use backend::AnyConnectionBackend;\n\nmod backend;\nmod executor;\n\n/// A connection to _any_ SQLx database.\n///\n/// The database driver used is determined by the scheme\n/// of the connection url.\n///\n/// ```text\n/// postgres://postgres@localhost/test\n/// sqlite://a.sqlite\n/// ```\n#[derive(Debug)]\npub struct AnyConnection {\n    pub(crate) backend: Box<dyn AnyConnectionBackend>,\n}\n\nimpl AnyConnection {\n    /// Returns the name of the database backend in use (e.g. PostgreSQL, MySQL, SQLite, etc.)\n    pub fn backend_name(&self) -> &str {\n        self.backend.name()\n    }\n\n    pub(crate) fn connect(options: &AnyConnectOptions) -> BoxFuture<'_, crate::Result<Self>> {\n        Box::pin(async {\n            let driver = crate::any::driver::from_url(&options.database_url)?;\n            (*driver.connect)(options, None).await\n        })\n    }\n\n    /// UNSTABLE: for use with `sqlx-cli`\n    ///\n    /// Connect to the database, and instruct the nested driver to\n    /// read options from the sqlx.toml file as appropriate.\n    #[doc(hidden)]\n    pub async fn connect_with_driver_config(\n        url: &str,\n        driver_config: &config::drivers::Config,\n    ) -> Result<Self, Error>\n    where\n        Self: Sized,\n    {\n        let options: AnyConnectOptions = url.parse()?;\n\n        let driver = crate::any::driver::from_url(&options.database_url)?;\n        (*driver.connect)(&options, Some(driver_config)).await\n    }\n\n    pub(crate) fn connect_with_db<'a, DB: Database>(\n        options: &'a AnyConnectOptions,\n        driver_config: Option<&'a config::drivers::Config>,\n    ) -> BoxFuture<'a, crate::Result<Self>>\n    where\n        DB::Connection: AnyConnectionBackend,\n        <DB::Connection as Connection>::Options:\n            for<'b> TryFrom<&'b AnyConnectOptions, Error = Error>,\n    {\n        let res = TryFrom::try_from(options);\n\n        Box::pin(async move {\n            let mut options: <DB::Connection as Connection>::Options = res?;\n\n            if let Some(config) = driver_config {\n                options = options.__unstable_apply_driver_config(config)?;\n            }\n\n            Ok(AnyConnection {\n                backend: Box::new(options.connect().await?),\n            })\n        })\n    }\n\n    #[cfg(feature = \"migrate\")]\n    pub(crate) fn get_migrate(\n        &mut self,\n    ) -> crate::Result<&mut (dyn crate::migrate::Migrate + Send + 'static)> {\n        self.backend.as_migrate()\n    }\n}\n\nimpl Connection for AnyConnection {\n    type Database = Any;\n\n    type Options = AnyConnectOptions;\n\n    fn close(self) -> impl Future<Output = Result<(), Error>> + Send + 'static {\n        self.backend.close()\n    }\n\n    fn close_hard(self) -> impl Future<Output = Result<(), Error>> + Send + 'static {\n        self.backend.close()\n    }\n\n    fn ping(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        self.backend.ping()\n    }\n\n    fn begin(\n        &mut self,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        Transaction::begin(self, None)\n    }\n\n    fn begin_with(\n        &mut self,\n        statement: impl SqlSafeStr,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        Transaction::begin(self, Some(statement.into_sql_str()))\n    }\n\n    fn cached_statements_size(&self) -> usize {\n        self.backend.cached_statements_size()\n    }\n\n    fn clear_cached_statements(&mut self) -> impl Future<Output = crate::Result<()>> + Send + '_ {\n        self.backend.clear_cached_statements()\n    }\n\n    fn shrink_buffers(&mut self) {\n        self.backend.shrink_buffers()\n    }\n\n    #[doc(hidden)]\n    fn flush(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        self.backend.flush()\n    }\n\n    #[doc(hidden)]\n    fn should_flush(&self) -> bool {\n        self.backend.should_flush()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/database.rs",
    "content": "use crate::any::{\n    AnyArgumentBuffer, AnyArguments, AnyColumn, AnyConnection, AnyQueryResult, AnyRow,\n    AnyStatement, AnyTransactionManager, AnyTypeInfo, AnyValue, AnyValueRef,\n};\nuse crate::database::{Database, HasStatementCache};\n\n/// Opaque database driver. Capable of being used in place of any SQLx database driver. The actual\n/// driver used will be selected at runtime, from the connection url.\n#[derive(Debug)]\npub struct Any;\n\nimpl Database for Any {\n    type Connection = AnyConnection;\n\n    type TransactionManager = AnyTransactionManager;\n\n    type Row = AnyRow;\n\n    type QueryResult = AnyQueryResult;\n\n    type Column = AnyColumn;\n\n    type TypeInfo = AnyTypeInfo;\n\n    type Value = AnyValue;\n    type ValueRef<'r> = AnyValueRef<'r>;\n\n    type Arguments = AnyArguments;\n    type ArgumentBuffer = AnyArgumentBuffer;\n\n    type Statement = AnyStatement;\n\n    const NAME: &'static str = \"Any\";\n\n    const URL_SCHEMES: &'static [&'static str] = &[];\n}\n\n// This _may_ be true, depending on the selected database\nimpl HasStatementCache for Any {}\n"
  },
  {
    "path": "sqlx-core/src/any/driver.rs",
    "content": "use crate::any::connection::AnyConnectionBackend;\nuse crate::any::{AnyConnectOptions, AnyConnection};\nuse crate::common::DebugFn;\nuse crate::connection::Connection;\nuse crate::database::Database;\nuse crate::{config, Error};\nuse futures_core::future::BoxFuture;\nuse std::fmt::{Debug, Formatter};\nuse std::sync::OnceLock;\nuse url::Url;\n\nstatic DRIVERS: OnceLock<&'static [AnyDriver]> = OnceLock::new();\n\n#[macro_export]\nmacro_rules! declare_driver_with_optional_migrate {\n    ($name:ident = $db:path) => {\n        #[cfg(feature = \"migrate\")]\n        pub const $name: $crate::any::driver::AnyDriver =\n            $crate::any::driver::AnyDriver::with_migrate::<$db>();\n\n        #[cfg(not(feature = \"migrate\"))]\n        pub const $name: $crate::any::driver::AnyDriver =\n            $crate::any::driver::AnyDriver::without_migrate::<$db>();\n    };\n}\n\n#[non_exhaustive]\npub struct AnyDriver {\n    pub(crate) name: &'static str,\n    pub(crate) url_schemes: &'static [&'static str],\n    pub(crate) connect: DebugFn<\n        for<'a> fn(\n            &'a AnyConnectOptions,\n            Option<&'a config::drivers::Config>,\n        ) -> BoxFuture<'a, crate::Result<AnyConnection>>,\n    >,\n    pub(crate) migrate_database: Option<AnyMigrateDatabase>,\n}\n\nimpl AnyDriver {\n    pub const fn without_migrate<DB: Database>() -> Self\n    where\n        DB::Connection: AnyConnectionBackend,\n        <DB::Connection as Connection>::Options:\n            for<'a> TryFrom<&'a AnyConnectOptions, Error = Error>,\n    {\n        Self {\n            name: DB::NAME,\n            url_schemes: DB::URL_SCHEMES,\n            connect: DebugFn(AnyConnection::connect_with_db::<DB>),\n            migrate_database: None,\n        }\n    }\n\n    #[cfg(not(feature = \"migrate\"))]\n    pub const fn with_migrate<DB: Database>() -> Self\n    where\n        DB::Connection: AnyConnectionBackend,\n        <DB::Connection as Connection>::Options:\n            for<'a> TryFrom<&'a AnyConnectOptions, Error = Error>,\n    {\n        Self::without_migrate::<DB>()\n    }\n\n    #[cfg(feature = \"migrate\")]\n    pub const fn with_migrate<DB: Database + crate::migrate::MigrateDatabase>() -> Self\n    where\n        DB::Connection: AnyConnectionBackend,\n        <DB::Connection as Connection>::Options:\n            for<'a> TryFrom<&'a AnyConnectOptions, Error = Error>,\n    {\n        Self {\n            migrate_database: Some(AnyMigrateDatabase {\n                create_database: DebugFn(|url| Box::pin(DB::create_database(url))),\n                database_exists: DebugFn(|url| Box::pin(DB::database_exists(url))),\n                drop_database: DebugFn(|url| Box::pin(DB::drop_database(url))),\n                force_drop_database: DebugFn(|url| Box::pin(DB::force_drop_database(url))),\n            }),\n            ..Self::without_migrate::<DB>()\n        }\n    }\n\n    pub fn get_migrate_database(&self) -> crate::Result<&AnyMigrateDatabase> {\n        self.migrate_database.as_ref()\n            .ok_or_else(|| Error::Configuration(format!(\"{} driver does not support migrations or the `migrate` feature was not enabled for it\", self.name).into()))\n    }\n}\n\nimpl Debug for AnyDriver {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"AnyDriver\")\n            .field(\"name\", &self.name)\n            .field(\"url_schemes\", &self.url_schemes)\n            .finish()\n    }\n}\n\npub struct AnyMigrateDatabase {\n    create_database: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<()>>>,\n    database_exists: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<bool>>>,\n    drop_database: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<()>>>,\n    force_drop_database: DebugFn<fn(&str) -> BoxFuture<'_, crate::Result<()>>>,\n}\n\nimpl AnyMigrateDatabase {\n    pub fn create_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> {\n        (self.create_database)(url)\n    }\n\n    pub fn database_exists<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<bool>> {\n        (self.database_exists)(url)\n    }\n\n    pub fn drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> {\n        (self.drop_database)(url)\n    }\n\n    pub fn force_drop_database<'a>(&self, url: &'a str) -> BoxFuture<'a, crate::Result<()>> {\n        (self.force_drop_database)(url)\n    }\n}\n\n/// Install the list of drivers for [`AnyConnection`] to use.\n///\n/// Must be called before an `AnyConnection` or `AnyPool` can be connected.\n///\n/// ### Errors\n/// If called more than once.\npub fn install_drivers(\n    drivers: &'static [AnyDriver],\n) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {\n    DRIVERS\n        .set(drivers)\n        .map_err(|_| \"drivers already installed\".into())\n}\n\n#[cfg(feature = \"migrate\")]\npub(crate) fn from_url_str(url: &str) -> crate::Result<&'static AnyDriver> {\n    from_url(&url.parse().map_err(Error::config)?)\n}\n\npub(crate) fn from_url(url: &Url) -> crate::Result<&'static AnyDriver> {\n    let scheme = url.scheme();\n\n    let drivers: &[AnyDriver] = DRIVERS\n        .get()\n        .expect(\"No drivers installed. Please see the documentation in `sqlx::any` for details.\");\n\n    drivers\n        .iter()\n        .find(|driver| driver.url_schemes.contains(&url.scheme()))\n        .ok_or_else(|| {\n            Error::Configuration(format!(\"no driver found for URL scheme {scheme:?}\").into())\n        })\n}\n"
  },
  {
    "path": "sqlx-core/src/any/error.rs",
    "content": "use std::any::type_name;\n\nuse crate::any::type_info::AnyTypeInfo;\nuse crate::any::Any;\nuse crate::error::BoxDynError;\nuse crate::type_info::TypeInfo;\nuse crate::types::Type;\n\npub(super) fn mismatched_types<T: Type<Any>>(ty: &AnyTypeInfo) -> BoxDynError {\n    format!(\n        \"mismatched types; Rust type `{}` is not compatible with SQL type `{}`\",\n        type_name::<T>(),\n        ty.name()\n    )\n    .into()\n}\n"
  },
  {
    "path": "sqlx-core/src/any/kind.rs",
    "content": "// Annoying how deprecation warnings trigger in the same module as the deprecated item.\n#![allow(deprecated)]\n// Cargo features are broken in this file.\n// `AnyKind` may return at some point but it won't be a simple enum.\n#![allow(unexpected_cfgs)]\n\nuse crate::error::Error;\nuse std::str::FromStr;\n\n#[deprecated = \"not used or returned by any API\"]\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\npub enum AnyKind {\n    #[cfg(feature = \"postgres\")]\n    Postgres,\n\n    #[cfg(feature = \"mysql\")]\n    MySql,\n\n    #[cfg(feature = \"_sqlite\")]\n    Sqlite,\n\n    #[cfg(feature = \"mssql\")]\n    Mssql,\n}\n\nimpl FromStr for AnyKind {\n    type Err = Error;\n\n    fn from_str(url: &str) -> Result<Self, Self::Err> {\n        match url {\n            #[cfg(feature = \"postgres\")]\n            _ if url.starts_with(\"postgres:\") || url.starts_with(\"postgresql:\") => {\n                Ok(AnyKind::Postgres)\n            }\n\n            #[cfg(not(feature = \"postgres\"))]\n            _ if url.starts_with(\"postgres:\") || url.starts_with(\"postgresql:\") => {\n                Err(Error::Configuration(\"database URL has the scheme of a PostgreSQL database but the `postgres` feature is not enabled\".into()))\n            }\n\n            #[cfg(feature = \"mysql\")]\n            _ if url.starts_with(\"mysql:\") || url.starts_with(\"mariadb:\") => {\n                Ok(AnyKind::MySql)\n            }\n\n            #[cfg(not(feature = \"mysql\"))]\n            _ if url.starts_with(\"mysql:\") || url.starts_with(\"mariadb:\") => {\n                Err(Error::Configuration(\"database URL has the scheme of a MySQL database but the `mysql` feature is not enabled\".into()))\n            }\n\n            #[cfg(feature = \"_sqlite\")]\n            _ if url.starts_with(\"sqlite:\") => {\n                Ok(AnyKind::Sqlite)\n            }\n\n            #[cfg(not(feature = \"_sqlite\"))]\n            _ if url.starts_with(\"sqlite:\") => {\n                Err(Error::Configuration(\"database URL has the scheme of a SQLite database but the `sqlite` feature is not enabled\".into()))\n            }\n\n            #[cfg(feature = \"mssql\")]\n            _ if url.starts_with(\"mssql:\") || url.starts_with(\"sqlserver:\") => {\n                Ok(AnyKind::Mssql)\n            }\n\n            #[cfg(not(feature = \"mssql\"))]\n            _ if url.starts_with(\"mssql:\") || url.starts_with(\"sqlserver:\") => {\n                Err(Error::Configuration(\"database URL has the scheme of a MSSQL database but the `mssql` feature is not enabled\".into()))\n            }\n\n            _ => Err(Error::Configuration(format!(\"unrecognized database url: {url:?}\").into()))\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/migrate.rs",
    "content": "use crate::any::driver;\nuse crate::any::{Any, AnyConnection};\nuse crate::error::Error;\nuse crate::migrate::{AppliedMigration, Migrate, MigrateDatabase, MigrateError, Migration};\nuse futures_core::future::BoxFuture;\nuse std::time::Duration;\n\nimpl MigrateDatabase for Any {\n    async fn create_database(url: &str) -> Result<(), Error> {\n        driver::from_url_str(url)?\n            .get_migrate_database()?\n            .create_database(url)\n            .await\n    }\n\n    async fn database_exists(url: &str) -> Result<bool, Error> {\n        driver::from_url_str(url)?\n            .get_migrate_database()?\n            .database_exists(url)\n            .await\n    }\n\n    async fn drop_database(url: &str) -> Result<(), Error> {\n        driver::from_url_str(url)?\n            .get_migrate_database()?\n            .drop_database(url)\n            .await\n    }\n\n    async fn force_drop_database(url: &str) -> Result<(), Error> {\n        driver::from_url_str(url)?\n            .get_migrate_database()?\n            .force_drop_database(url)\n            .await\n    }\n}\n\nimpl Migrate for AnyConnection {\n    fn create_schema_if_not_exists<'e>(\n        &'e mut self,\n        schema_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async {\n            self.get_migrate()?\n                .create_schema_if_not_exists(schema_name)\n                .await\n        })\n    }\n\n    fn ensure_migrations_table<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async {\n            self.get_migrate()?\n                .ensure_migrations_table(table_name)\n                .await\n        })\n    }\n\n    fn dirty_version<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Option<i64>, MigrateError>> {\n        Box::pin(async { self.get_migrate()?.dirty_version(table_name).await })\n    }\n\n    fn list_applied_migrations<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>> {\n        Box::pin(async {\n            self.get_migrate()?\n                .list_applied_migrations(table_name)\n                .await\n        })\n    }\n\n    fn lock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async { self.get_migrate()?.lock().await })\n    }\n\n    fn unlock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async { self.get_migrate()?.unlock().await })\n    }\n\n    fn apply<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async { self.get_migrate()?.apply(table_name, migration).await })\n    }\n\n    fn revert<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async { self.get_migrate()?.revert(table_name, migration).await })\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/mod.rs",
    "content": "//! **SEE DOCUMENTATION BEFORE USE**. Generic database driver with the specific driver selected at runtime.\n//!\n//! The underlying database drivers are chosen at runtime from the list set via\n//! [`install_drivers`][self::driver::install_drivers]. Any use of `AnyConnection` or `AnyPool`\n//! without this will panic.\nuse crate::executor::Executor;\n\nmod arguments;\npub(crate) mod column;\nmod connection;\nmod database;\nmod error;\nmod kind;\nmod options;\nmod query_result;\npub(crate) mod row;\nmod statement;\nmod transaction;\npub(crate) mod type_info;\npub mod types;\npub(crate) mod value;\n\npub mod driver;\n\n#[cfg(feature = \"migrate\")]\nmod migrate;\n\npub use arguments::{AnyArgumentBuffer, AnyArguments};\npub use column::AnyColumn;\npub use connection::AnyConnection;\n// Used internally in `sqlx-macros`\n\nuse crate::encode::Encode;\npub use connection::AnyConnectionBackend;\npub use database::Any;\n#[allow(deprecated)]\npub use kind::AnyKind;\npub use options::AnyConnectOptions;\npub use query_result::AnyQueryResult;\npub use row::AnyRow;\npub use statement::AnyStatement;\npub use transaction::AnyTransactionManager;\npub use type_info::{AnyTypeInfo, AnyTypeInfoKind};\npub use value::{AnyValue, AnyValueRef};\n\nuse crate::types::Type;\n#[doc(hidden)]\npub use value::AnyValueKind;\n\npub type AnyPool = crate::pool::Pool<Any>;\n\npub type AnyPoolOptions = crate::pool::PoolOptions<Any>;\n\n/// An alias for [`Executor<'_, Database = Any>`][Executor].\npub trait AnyExecutor<'c>: Executor<'c, Database = Any> {}\nimpl<'c, T: Executor<'c, Database = Any>> AnyExecutor<'c> for T {}\n\n// NOTE: required due to the lack of lazy normalization\nimpl_into_arguments_for_arguments!(AnyArguments);\n// impl_executor_for_pool_connection!(Any, AnyConnection, AnyRow);\n// impl_executor_for_transaction!(Any, AnyRow);\nimpl_acquire!(Any, AnyConnection);\nimpl_column_index_for_row!(AnyRow);\nimpl_column_index_for_statement!(AnyStatement);\n// impl_into_maybe_pool!(Any, AnyConnection);\n\n// required because some databases have a different handling of NULL\nimpl<'q, T> Encode<'q, Any> for Option<T>\nwhere\n    T: Encode<'q, Any> + 'q + Type<Any>,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut AnyArgumentBuffer,\n    ) -> Result<crate::encode::IsNull, crate::error::BoxDynError> {\n        if let Some(value) = self {\n            value.encode_by_ref(buf)\n        } else {\n            buf.0.push(AnyValueKind::Null(T::type_info().kind));\n            Ok(crate::encode::IsNull::Yes)\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/options.rs",
    "content": "use crate::any::AnyConnection;\nuse crate::connection::{ConnectOptions, LogSettings};\nuse crate::error::Error;\nuse log::LevelFilter;\nuse std::future::Future;\nuse std::str::FromStr;\nuse std::time::Duration;\nuse url::Url;\n\n/// Opaque options for connecting to a database. These may only be constructed by parsing from\n/// a connection url.\n///\n/// ```text\n/// postgres://postgres:password@localhost/database\n/// mysql://root:password@localhost/database\n/// ```\n#[derive(Debug, Clone)]\n#[non_exhaustive]\npub struct AnyConnectOptions {\n    pub database_url: Url,\n    pub log_settings: LogSettings,\n}\nimpl FromStr for AnyConnectOptions {\n    type Err = Error;\n\n    fn from_str(url: &str) -> Result<Self, Self::Err> {\n        Ok(AnyConnectOptions {\n            database_url: url\n                .parse::<Url>()\n                .map_err(|e| Error::Configuration(e.into()))?,\n            log_settings: LogSettings::default(),\n        })\n    }\n}\n\nimpl ConnectOptions for AnyConnectOptions {\n    type Connection = AnyConnection;\n\n    fn from_url(url: &Url) -> Result<Self, Error> {\n        Ok(AnyConnectOptions {\n            database_url: url.clone(),\n            log_settings: LogSettings::default(),\n        })\n    }\n\n    fn to_url_lossy(&self) -> Url {\n        self.database_url.clone()\n    }\n\n    #[inline]\n    fn connect(&self) -> impl Future<Output = Result<AnyConnection, Error>> + Send + '_ {\n        AnyConnection::connect(self)\n    }\n\n    fn log_statements(mut self, level: LevelFilter) -> Self {\n        self.log_settings.statements_level = level;\n        self\n    }\n\n    fn log_slow_statements(mut self, level: LevelFilter, duration: Duration) -> Self {\n        self.log_settings.slow_statements_level = level;\n        self.log_settings.slow_statements_duration = duration;\n        self\n    }\n}\n\nimpl AnyConnectOptions {}\n"
  },
  {
    "path": "sqlx-core/src/any/query_result.rs",
    "content": "use std::iter::{Extend, IntoIterator};\n\n#[derive(Debug, Default)]\npub struct AnyQueryResult {\n    #[doc(hidden)]\n    pub rows_affected: u64,\n    #[doc(hidden)]\n    pub last_insert_id: Option<i64>,\n}\n\nimpl AnyQueryResult {\n    pub fn rows_affected(&self) -> u64 {\n        self.rows_affected\n    }\n\n    pub fn last_insert_id(&self) -> Option<i64> {\n        self.last_insert_id\n    }\n}\n\nimpl Extend<AnyQueryResult> for AnyQueryResult {\n    fn extend<T: IntoIterator<Item = AnyQueryResult>>(&mut self, iter: T) {\n        for elem in iter {\n            self.rows_affected += elem.rows_affected;\n            self.last_insert_id = elem.last_insert_id;\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/row.rs",
    "content": "use crate::any::error::mismatched_types;\nuse crate::any::{Any, AnyColumn, AnyTypeInfo, AnyTypeInfoKind, AnyValue, AnyValueKind};\nuse crate::column::{Column, ColumnIndex};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::row::Row;\nuse crate::type_info::TypeInfo;\nuse crate::types::Type;\nuse crate::value::{Value, ValueRef};\nuse std::sync::Arc;\n\n#[derive(Clone)]\npub struct AnyRow {\n    #[doc(hidden)]\n    pub column_names: Arc<crate::HashMap<UStr, usize>>,\n    #[doc(hidden)]\n    pub columns: Vec<AnyColumn>,\n    #[doc(hidden)]\n    pub values: Vec<AnyValue>,\n}\n\nimpl Row for AnyRow {\n    type Database = Any;\n\n    fn columns(&self) -> &[AnyColumn] {\n        &self.columns\n    }\n\n    fn try_get_raw<I>(&self, index: I) -> Result<<Self::Database as Database>::ValueRef<'_>, Error>\n    where\n        I: ColumnIndex<Self>,\n    {\n        let index = index.index(self)?;\n        Ok(self\n            .values\n            .get(index)\n            .ok_or_else(|| Error::ColumnIndexOutOfBounds {\n                index,\n                len: self.columns.len(),\n            })?\n            .as_ref())\n    }\n\n    fn try_get<'r, T, I>(&'r self, index: I) -> Result<T, Error>\n    where\n        I: ColumnIndex<Self>,\n        T: Decode<'r, Self::Database> + Type<Self::Database>,\n    {\n        let value = self.try_get_raw(&index)?;\n        let ty = value.type_info();\n\n        if !value.is_null() && !ty.is_null() && !T::compatible(&ty) {\n            Err(mismatched_types::<T>(&ty))\n        } else {\n            T::decode(value)\n        }\n        .map_err(|source| Error::ColumnDecode {\n            index: format!(\"{index:?}\"),\n            source,\n        })\n    }\n}\n\nimpl ColumnIndex<AnyRow> for &'_ str {\n    fn index(&self, row: &AnyRow) -> Result<usize, Error> {\n        row.column_names\n            .get(*self)\n            .copied()\n            .ok_or_else(|| Error::ColumnNotFound(self.to_string()))\n    }\n}\n\nimpl AnyRow {\n    // This is not a `TryFrom` impl because trait impls are easy for users to accidentally\n    // become reliant upon, even if hidden, but we want to be able to change the bounds\n    // on this function as the `Any` driver gains support for more types.\n    //\n    // Also `column_names` needs to be passed by the driver to avoid making deep copies.\n    #[doc(hidden)]\n    pub fn map_from<'a, R: Row>(\n        row: &'a R,\n        column_names: Arc<crate::HashMap<UStr, usize>>,\n    ) -> Result<Self, Error>\n    where\n        usize: ColumnIndex<R>,\n        AnyTypeInfo: for<'b> TryFrom<&'b <R::Database as Database>::TypeInfo, Error = Error>,\n        AnyColumn: for<'b> TryFrom<&'b <R::Database as Database>::Column, Error = Error>,\n        bool: Type<R::Database> + Decode<'a, R::Database>,\n        i16: Type<R::Database> + Decode<'a, R::Database>,\n        i32: Type<R::Database> + Decode<'a, R::Database>,\n        i64: Type<R::Database> + Decode<'a, R::Database>,\n        f32: Type<R::Database> + Decode<'a, R::Database>,\n        f64: Type<R::Database> + Decode<'a, R::Database>,\n        String: Type<R::Database> + Decode<'a, R::Database>,\n        Vec<u8>: Type<R::Database> + Decode<'a, R::Database>,\n    {\n        let mut row_out = AnyRow {\n            column_names,\n            columns: Vec::with_capacity(row.columns().len()),\n            values: Vec::with_capacity(row.columns().len()),\n        };\n\n        for col in row.columns() {\n            let i = col.ordinal();\n\n            let any_col = AnyColumn::try_from(col)?;\n\n            let value = row.try_get_raw(i)?;\n\n            // Map based on the _value_ type info, not the column type info.\n            let type_info =\n                AnyTypeInfo::try_from(&value.type_info()).map_err(|e| Error::ColumnDecode {\n                    index: col.ordinal().to_string(),\n                    source: e.into(),\n                })?;\n\n            let value_kind = match type_info.kind {\n                k if value.is_null() => AnyValueKind::Null(k),\n                AnyTypeInfoKind::Null => AnyValueKind::Null(AnyTypeInfoKind::Null),\n                AnyTypeInfoKind::Bool => AnyValueKind::Bool(decode(value)?),\n                AnyTypeInfoKind::SmallInt => AnyValueKind::SmallInt(decode(value)?),\n                AnyTypeInfoKind::Integer => AnyValueKind::Integer(decode(value)?),\n                AnyTypeInfoKind::BigInt => AnyValueKind::BigInt(decode(value)?),\n                AnyTypeInfoKind::Real => AnyValueKind::Real(decode(value)?),\n                AnyTypeInfoKind::Double => AnyValueKind::Double(decode(value)?),\n                AnyTypeInfoKind::Blob => AnyValueKind::Blob(decode::<_, Vec<u8>>(value)?.into()),\n                AnyTypeInfoKind::Text => AnyValueKind::Text(decode::<_, String>(value)?.into()),\n            };\n\n            row_out.columns.push(any_col);\n            row_out.values.push(AnyValue { kind: value_kind });\n        }\n\n        Ok(row_out)\n    }\n}\n\nfn decode<'r, DB: Database, T: Decode<'r, DB>>(\n    valueref: <DB as Database>::ValueRef<'r>,\n) -> crate::Result<T> {\n    Decode::decode(valueref).map_err(Error::decode)\n}\n"
  },
  {
    "path": "sqlx-core/src/any/statement.rs",
    "content": "use crate::any::{Any, AnyArguments, AnyColumn, AnyTypeInfo};\nuse crate::column::ColumnIndex;\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::sql_str::SqlStr;\nuse crate::statement::Statement;\nuse crate::HashMap;\nuse either::Either;\nuse std::sync::Arc;\n\n#[derive(Clone)]\npub struct AnyStatement {\n    #[doc(hidden)]\n    pub sql: SqlStr,\n    #[doc(hidden)]\n    pub parameters: Option<Either<Vec<AnyTypeInfo>, usize>>,\n    #[doc(hidden)]\n    pub column_names: Arc<HashMap<UStr, usize>>,\n    #[doc(hidden)]\n    pub columns: Vec<AnyColumn>,\n}\n\nimpl Statement for AnyStatement {\n    type Database = Any;\n\n    fn into_sql(self) -> SqlStr {\n        self.sql\n    }\n\n    fn sql(&self) -> &SqlStr {\n        &self.sql\n    }\n\n    fn parameters(&self) -> Option<Either<&[AnyTypeInfo], usize>> {\n        match &self.parameters {\n            Some(Either::Left(types)) => Some(Either::Left(types)),\n            Some(Either::Right(count)) => Some(Either::Right(*count)),\n            None => None,\n        }\n    }\n\n    fn columns(&self) -> &[AnyColumn] {\n        &self.columns\n    }\n\n    impl_statement_query!(AnyArguments);\n}\n\nimpl ColumnIndex<AnyStatement> for &'_ str {\n    fn index(&self, statement: &AnyStatement) -> Result<usize, Error> {\n        statement\n            .column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n\nimpl AnyStatement {\n    #[doc(hidden)]\n    pub fn try_from_statement<S>(\n        statement: S,\n        column_names: Arc<HashMap<UStr, usize>>,\n    ) -> crate::Result<Self>\n    where\n        S: Statement,\n        AnyTypeInfo: for<'a> TryFrom<&'a <S::Database as Database>::TypeInfo, Error = Error>,\n        AnyColumn: for<'a> TryFrom<&'a <S::Database as Database>::Column, Error = Error>,\n    {\n        let parameters = match statement.parameters() {\n            Some(Either::Left(parameters)) => Some(Either::Left(\n                parameters\n                    .iter()\n                    .map(AnyTypeInfo::try_from)\n                    .collect::<Result<Vec<_>, _>>()?,\n            )),\n            Some(Either::Right(count)) => Some(Either::Right(count)),\n            None => None,\n        };\n\n        let columns = statement\n            .columns()\n            .iter()\n            .map(AnyColumn::try_from)\n            .collect::<Result<Vec<_>, _>>()?;\n\n        Ok(Self {\n            sql: statement.into_sql(),\n            columns,\n            column_names,\n            parameters,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/transaction.rs",
    "content": "use std::future::Future;\n\nuse crate::any::{Any, AnyConnection};\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::sql_str::SqlStr;\nuse crate::transaction::TransactionManager;\n\npub struct AnyTransactionManager;\n\nimpl TransactionManager for AnyTransactionManager {\n    type Database = Any;\n\n    fn begin(\n        conn: &mut AnyConnection,\n        statement: Option<SqlStr>,\n    ) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        conn.backend.begin(statement)\n    }\n\n    fn commit(conn: &mut AnyConnection) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        conn.backend.commit()\n    }\n\n    fn rollback(conn: &mut AnyConnection) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        conn.backend.rollback()\n    }\n\n    fn start_rollback(conn: &mut AnyConnection) {\n        conn.backend.start_rollback()\n    }\n\n    fn get_transaction_depth(conn: &<Self::Database as Database>::Connection) -> usize {\n        conn.backend.get_transaction_depth()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/type_info.rs",
    "content": "use std::fmt::{self, Display, Formatter};\n\nuse crate::type_info::TypeInfo;\n\nuse AnyTypeInfoKind::*;\n\n#[derive(Debug, Clone, PartialEq)]\npub struct AnyTypeInfo {\n    #[doc(hidden)]\n    pub kind: AnyTypeInfoKind,\n}\n\nimpl AnyTypeInfo {\n    pub fn kind(&self) -> AnyTypeInfoKind {\n        self.kind\n    }\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\npub enum AnyTypeInfoKind {\n    Null,\n    Bool,\n    SmallInt,\n    Integer,\n    BigInt,\n    Real,\n    Double,\n    Text,\n    Blob,\n}\n\nimpl TypeInfo for AnyTypeInfo {\n    fn is_null(&self) -> bool {\n        self.kind == Null\n    }\n\n    fn name(&self) -> &str {\n        use AnyTypeInfoKind::*;\n\n        match self.kind {\n            Bool => \"BOOLEAN\",\n            SmallInt => \"SMALLINT\",\n            Integer => \"INTEGER\",\n            BigInt => \"BIGINT\",\n            Real => \"REAL\",\n            Double => \"DOUBLE\",\n            Text => \"TEXT\",\n            Blob => \"BLOB\",\n            Null => \"NULL\",\n        }\n    }\n}\n\nimpl Display for AnyTypeInfo {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.write_str(self.name())\n    }\n}\n\nimpl AnyTypeInfoKind {\n    pub fn is_integer(&self) -> bool {\n        matches!(self, SmallInt | Integer | BigInt)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/types/blob.rs",
    "content": "use crate::any::{Any, AnyTypeInfo, AnyTypeInfoKind, AnyValueKind};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse std::sync::Arc;\n\nimpl Type<Any> for [u8] {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::Blob,\n        }\n    }\n}\n\nimpl<'q> Encode<'q, Any> for &'q [u8] {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Blob(Arc::new(self.to_vec())));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for &'r [u8] {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            AnyValueKind::Blob(blob) => Ok(blob.as_slice()),\n            other => other.unexpected(),\n        }\n    }\n}\n\nimpl Type<Any> for Vec<u8> {\n    fn type_info() -> AnyTypeInfo {\n        <[u8] as Type<Any>>::type_info()\n    }\n}\n\nimpl Encode<'_, Any> for Vec<u8> {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Blob(Arc::new(self.clone())));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for Vec<u8> {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            AnyValueKind::Blob(blob) => Ok(blob.as_ref().clone()),\n            other => other.unexpected(),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/types/bool.rs",
    "content": "use crate::any::{Any, AnyTypeInfo, AnyTypeInfoKind, AnyValueKind};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\n\nimpl Type<Any> for bool {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::Bool,\n        }\n    }\n}\n\nimpl Encode<'_, Any> for bool {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Bool(*self));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for bool {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            AnyValueKind::Bool(b) => Ok(*b),\n            other => other.unexpected(),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/types/float.rs",
    "content": "use crate::any::{Any, AnyArgumentBuffer, AnyTypeInfo, AnyTypeInfoKind, AnyValueKind, AnyValueRef};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\n\nimpl Type<Any> for f32 {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::Real,\n        }\n    }\n}\n\nimpl Encode<'_, Any> for f32 {\n    fn encode_by_ref(&self, buf: &mut AnyArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Real(*self));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for f32 {\n    fn decode(value: AnyValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            AnyValueKind::Real(r) => Ok(*r),\n            other => other.unexpected(),\n        }\n    }\n}\n\nimpl Type<Any> for f64 {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::Double,\n        }\n    }\n}\n\nimpl Encode<'_, Any> for f64 {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Double(*self));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for f64 {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            // Widening is safe\n            AnyValueKind::Real(r) => Ok(*r as f64),\n            AnyValueKind::Double(d) => Ok(*d),\n            other => other.unexpected(),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/types/int.rs",
    "content": "use crate::any::{Any, AnyTypeInfo, AnyTypeInfoKind, AnyValueKind};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\n\nimpl Type<Any> for i16 {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::SmallInt,\n        }\n    }\n\n    fn compatible(ty: &AnyTypeInfo) -> bool {\n        ty.kind().is_integer()\n    }\n}\n\nimpl Encode<'_, Any> for i16 {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::SmallInt(*self));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for i16 {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        value.kind.try_integer()\n    }\n}\n\nimpl Type<Any> for i32 {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::Integer,\n        }\n    }\n\n    fn compatible(ty: &AnyTypeInfo) -> bool {\n        ty.kind().is_integer()\n    }\n}\n\nimpl Encode<'_, Any> for i32 {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Integer(*self));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for i32 {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        value.kind.try_integer()\n    }\n}\n\nimpl Type<Any> for i64 {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::BigInt,\n        }\n    }\n\n    fn compatible(ty: &AnyTypeInfo) -> bool {\n        ty.kind().is_integer()\n    }\n}\n\nimpl Encode<'_, Any> for i64 {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::BigInt(*self));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for i64 {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        value.kind.try_integer()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/types/mod.rs",
    "content": "//! Conversions between Rust and standard **SQL** types.\n//!\n//! # Types\n//!\n//! | Rust type                             | SQL type(s)                                          |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bool`                                | BOOLEAN                                              |\n//! | `i16`                                 | SMALLINT                                             |\n//! | `i32`                                 | INT                                                  |\n//! | `i64`                                 | BIGINT                                               |\n//! | `f32`                                 | FLOAT                                                |\n//! | `f64`                                 | DOUBLE                                               |\n//! | `&str`, [`String`]                    | VARCHAR, CHAR, TEXT                                  |\n//!\n//! # Nullable\n//!\n//! In addition, `Option<T>` is supported where `T` implements `Type`. An `Option<T>` represents\n//! a potentially `NULL` value from SQL.\n\nmod blob;\nmod bool;\nmod float;\nmod int;\nmod str;\n\n#[test]\nfn test_type_impls() {\n    use crate::any::Any;\n    use crate::decode::Decode;\n    use crate::encode::Encode;\n    use crate::types::Type;\n\n    fn has_type<T>()\n    where\n        T: Type<Any>,\n        for<'a> T: Encode<'a, Any>,\n        for<'a> T: Decode<'a, Any>,\n    {\n    }\n\n    has_type::<bool>();\n\n    has_type::<i16>();\n    has_type::<i32>();\n    has_type::<i64>();\n\n    has_type::<f32>();\n    has_type::<f64>();\n\n    // These imply that there are also impls for the equivalent slice types.\n    has_type::<Vec<u8>>();\n    has_type::<String>();\n}\n"
  },
  {
    "path": "sqlx-core/src/any/types/str.rs",
    "content": "use crate::any::types::str;\nuse crate::any::{Any, AnyTypeInfo, AnyTypeInfoKind, AnyValueKind};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse std::sync::Arc;\n\nimpl Type<Any> for str {\n    fn type_info() -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: AnyTypeInfoKind::Text,\n        }\n    }\n}\n\nimpl<'a> Encode<'a, Any> for &'a str {\n    fn encode(self, buf: &mut <Any as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError>\n    where\n        Self: Sized,\n    {\n        buf.0.push(AnyValueKind::Text(Arc::new(self.into())));\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        (*self).encode(buf)\n    }\n}\n\nimpl<'a> Decode<'a, Any> for &'a str {\n    fn decode(value: <Any as Database>::ValueRef<'a>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            AnyValueKind::Text(text) => Ok(text.as_str()),\n            other => other.unexpected(),\n        }\n    }\n}\n\nimpl Type<Any> for String {\n    fn type_info() -> AnyTypeInfo {\n        <str as Type<Any>>::type_info()\n    }\n}\n\nimpl Encode<'_, Any> for String {\n    fn encode(self, buf: &mut <Any as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Text(Arc::new(self)));\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(\n        &self,\n        buf: &mut <Any as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        buf.0.push(AnyValueKind::Text(Arc::new(self.clone())));\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Any> for String {\n    fn decode(value: <Any as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.kind {\n            AnyValueKind::Text(text) => Ok(text.to_string()),\n            other => other.unexpected(),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/any/value.rs",
    "content": "use crate::any::{Any, AnyTypeInfo, AnyTypeInfoKind};\nuse crate::database::Database;\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::value::{Value, ValueRef};\nuse std::borrow::Cow;\nuse std::sync::Arc;\n\n#[derive(Clone, Debug)]\n#[non_exhaustive]\npub enum AnyValueKind {\n    Null(AnyTypeInfoKind),\n    Bool(bool),\n    SmallInt(i16),\n    Integer(i32),\n    BigInt(i64),\n    Real(f32),\n    Double(f64),\n    Text(Arc<String>),\n    TextSlice(Arc<str>),\n    Blob(Arc<Vec<u8>>),\n}\n\nimpl AnyValueKind {\n    fn type_info(&self) -> AnyTypeInfo {\n        AnyTypeInfo {\n            kind: match self {\n                AnyValueKind::Null(_) => AnyTypeInfoKind::Null,\n                AnyValueKind::Bool(_) => AnyTypeInfoKind::Bool,\n                AnyValueKind::SmallInt(_) => AnyTypeInfoKind::SmallInt,\n                AnyValueKind::Integer(_) => AnyTypeInfoKind::Integer,\n                AnyValueKind::BigInt(_) => AnyTypeInfoKind::BigInt,\n                AnyValueKind::Real(_) => AnyTypeInfoKind::Real,\n                AnyValueKind::Double(_) => AnyTypeInfoKind::Double,\n                AnyValueKind::Text(_) => AnyTypeInfoKind::Text,\n                AnyValueKind::TextSlice(_) => AnyTypeInfoKind::Text,\n                AnyValueKind::Blob(_) => AnyTypeInfoKind::Blob,\n            },\n        }\n    }\n\n    pub(in crate::any) fn unexpected<Expected: Type<Any>>(&self) -> Result<Expected, BoxDynError> {\n        Err(format!(\"expected {}, got {:?}\", Expected::type_info(), self).into())\n    }\n\n    pub(in crate::any) fn try_integer<T>(&self) -> Result<T, BoxDynError>\n    where\n        T: Type<Any> + TryFrom<i16> + TryFrom<i32> + TryFrom<i64>,\n        BoxDynError: From<<T as TryFrom<i16>>::Error>,\n        BoxDynError: From<<T as TryFrom<i32>>::Error>,\n        BoxDynError: From<<T as TryFrom<i64>>::Error>,\n    {\n        Ok(match self {\n            AnyValueKind::SmallInt(i) => (*i).try_into()?,\n            AnyValueKind::Integer(i) => (*i).try_into()?,\n            AnyValueKind::BigInt(i) => (*i).try_into()?,\n            _ => return self.unexpected(),\n        })\n    }\n}\n\n#[derive(Clone, Debug)]\npub struct AnyValue {\n    #[doc(hidden)]\n    pub kind: AnyValueKind,\n}\n\n#[derive(Clone, Debug)]\npub struct AnyValueRef<'a> {\n    pub(crate) kind: &'a AnyValueKind,\n}\n\nimpl Value for AnyValue {\n    type Database = Any;\n\n    fn as_ref(&self) -> <Self::Database as Database>::ValueRef<'_> {\n        AnyValueRef { kind: &self.kind }\n    }\n\n    fn type_info(&self) -> Cow<'_, <Self::Database as Database>::TypeInfo> {\n        Cow::Owned(self.kind.type_info())\n    }\n\n    fn is_null(&self) -> bool {\n        matches!(self.kind, AnyValueKind::Null(_))\n    }\n}\n\nimpl<'a> ValueRef<'a> for AnyValueRef<'a> {\n    type Database = Any;\n\n    fn to_owned(&self) -> <Self::Database as Database>::Value {\n        AnyValue {\n            kind: self.kind.clone(),\n        }\n    }\n\n    fn type_info(&self) -> Cow<'_, <Self::Database as Database>::TypeInfo> {\n        Cow::Owned(self.kind.type_info())\n    }\n\n    fn is_null(&self) -> bool {\n        matches!(self.kind, AnyValueKind::Null(_))\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/arguments.rs",
    "content": "//! Types and traits for passing arguments to SQL queries.\n\nuse crate::database::Database;\nuse crate::encode::Encode;\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse std::fmt::{self, Write};\n\n/// A tuple of arguments to be sent to the database.\n// This lint is designed for general collections, but `Arguments` is not meant to be as such.\n#[allow(clippy::len_without_is_empty)]\npub trait Arguments: Send + Sized + Default {\n    type Database: Database;\n\n    /// Reserves the capacity for at least `additional` more values (of `size` total bytes) to\n    /// be added to the arguments without a reallocation.\n    fn reserve(&mut self, additional: usize, size: usize);\n\n    /// Add the value to the end of the arguments.\n    fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'t, Self::Database> + Type<Self::Database>;\n\n    /// The number of arguments that were already added.\n    fn len(&self) -> usize;\n\n    fn format_placeholder<W: Write>(&self, writer: &mut W) -> fmt::Result {\n        writer.write_str(\"?\")\n    }\n}\n\npub trait IntoArguments<DB: Database>: Sized + Send {\n    fn into_arguments(self) -> <DB as Database>::Arguments;\n}\n\n// NOTE: required due to lack of lazy normalization\n#[macro_export]\nmacro_rules! impl_into_arguments_for_arguments {\n    ($Arguments:path) => {\n        impl\n            $crate::arguments::IntoArguments<<$Arguments as $crate::arguments::Arguments>::Database>\n            for $Arguments\n        {\n            fn into_arguments(self) -> $Arguments {\n                self\n            }\n        }\n    };\n}\n\n/// used by the query macros to prevent supernumerary `.bind()` calls\npub struct ImmutableArguments<DB: Database>(pub <DB as Database>::Arguments);\n\nimpl<DB: Database> IntoArguments<DB> for ImmutableArguments<DB> {\n    fn into_arguments(self) -> <DB as Database>::Arguments {\n        self.0\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/column.rs",
    "content": "use crate::database::Database;\nuse crate::error::Error;\n\nuse std::fmt::Debug;\nuse std::sync::Arc;\n\npub trait Column: 'static + Send + Sync + Debug {\n    type Database: Database<Column = Self>;\n\n    /// Gets the column ordinal.\n    ///\n    /// This can be used to unambiguously refer to this column within a row in case more than\n    /// one column have the same name\n    fn ordinal(&self) -> usize;\n\n    /// Gets the column name or alias.\n    ///\n    /// The column name is unreliable (and can change between database minor versions) if this\n    /// column is an expression that has not been aliased.\n    fn name(&self) -> &str;\n\n    /// Gets the type information for the column.\n    fn type_info(&self) -> &<Self::Database as Database>::TypeInfo;\n\n    /// If this column comes from a table, return the table and original column name.\n    ///\n    /// Returns [`ColumnOrigin::Expression`] if the column is the result of an expression\n    /// or else the source table could not be determined.\n    ///\n    /// Returns [`ColumnOrigin::Unknown`] if the database driver does not have that information,\n    /// or has not overridden this method.\n    // This method returns an owned value instead of a reference,\n    // to give the implementor more flexibility.\n    fn origin(&self) -> ColumnOrigin {\n        ColumnOrigin::Unknown\n    }\n}\n\n/// A [`Column`] that originates from a table.\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct TableColumn {\n    /// The name of the table (optionally schema-qualified) that the column comes from.\n    pub table: Arc<str>,\n    /// The original name of the column.\n    pub name: Arc<str>,\n}\n\n/// The possible statuses for our knowledge of the origin of a [`Column`].\n#[derive(Debug, Clone, Default)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub enum ColumnOrigin {\n    /// The column is known to originate from a table.\n    ///\n    /// Included is the table name and original column name.\n    Table(TableColumn),\n    /// The column originates from an expression, or else its origin could not be determined.\n    Expression,\n    /// The database driver does not know the column origin at this time.\n    ///\n    /// This may happen if:\n    /// * The connection is in the middle of executing a query,\n    ///   and cannot query the catalog to fetch this information.\n    /// * The connection does not have access to the database catalog.\n    /// * The implementation of [`Column`] did not override [`Column::origin()`].\n    #[default]\n    Unknown,\n}\n\nimpl ColumnOrigin {\n    /// Returns the true column origin, if known.\n    pub fn table_column(&self) -> Option<&TableColumn> {\n        if let Self::Table(table_column) = self {\n            Some(table_column)\n        } else {\n            None\n        }\n    }\n}\n\n/// A type that can be used to index into a [`Row`] or [`Statement`].\n///\n/// The [`get`] and [`try_get`] methods of [`Row`] accept any type that implements `ColumnIndex`.\n/// This trait is implemented for strings which are used to look up a column by name, and for\n/// `usize` which is used as a positional index into the row.\n///\n/// [`Row`]: crate::row::Row\n/// [`Statement`]: crate::statement::Statement\n/// [`get`]: crate::row::Row::get\n/// [`try_get`]: crate::row::Row::try_get\n///\npub trait ColumnIndex<T: ?Sized>: Debug {\n    /// Returns a valid positional index into the row or statement, [`ColumnIndexOutOfBounds`], or,\n    /// [`ColumnNotFound`].\n    ///\n    /// [`ColumnNotFound`]: Error::ColumnNotFound\n    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds\n    fn index(&self, container: &T) -> Result<usize, Error>;\n}\n\nimpl<T: ?Sized, I: ColumnIndex<T> + ?Sized> ColumnIndex<T> for &'_ I {\n    #[inline]\n    fn index(&self, row: &T) -> Result<usize, Error> {\n        (**self).index(row)\n    }\n}\n\n#[macro_export]\nmacro_rules! impl_column_index_for_row {\n    ($R:ident) => {\n        impl $crate::column::ColumnIndex<$R> for usize {\n            fn index(&self, row: &$R) -> Result<usize, $crate::error::Error> {\n                let len = $crate::row::Row::len(row);\n\n                if *self >= len {\n                    return Err($crate::error::Error::ColumnIndexOutOfBounds { len, index: *self });\n                }\n\n                Ok(*self)\n            }\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! impl_column_index_for_statement {\n    ($S:ident) => {\n        impl $crate::column::ColumnIndex<$S> for usize {\n            fn index(&self, statement: &$S) -> Result<usize, $crate::error::Error> {\n                let len = $crate::statement::Statement::columns(statement).len();\n\n                if *self >= len {\n                    return Err($crate::error::Error::ColumnIndexOutOfBounds { len, index: *self });\n                }\n\n                Ok(*self)\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "sqlx-core/src/common/mod.rs",
    "content": "mod statement_cache;\n\npub use statement_cache::StatementCache;\nuse std::fmt::{Debug, Formatter};\nuse std::ops::{Deref, DerefMut};\n\n/// A wrapper for `Fn`s that provides a debug impl that just says \"Function\"\npub struct DebugFn<F: ?Sized>(pub F);\n\nimpl<F: ?Sized> Deref for DebugFn<F> {\n    type Target = F;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<F: ?Sized> DerefMut for DebugFn<F> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\nimpl<F: ?Sized> Debug for DebugFn<F> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_tuple(\"Function\").finish()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/common/statement_cache.rs",
    "content": "use hashlink::lru_cache::LruCache;\n\n/// A cache for prepared statements. When full, the least recently used\n/// statement gets removed.\n#[derive(Debug)]\npub struct StatementCache<T> {\n    inner: LruCache<String, T>,\n}\n\nimpl<T> StatementCache<T> {\n    /// Create a new cache with the given capacity.\n    pub fn new(capacity: usize) -> Self {\n        Self {\n            inner: LruCache::new(capacity),\n        }\n    }\n\n    /// Returns a mutable reference to the value corresponding to the given key\n    /// in the cache, if any.\n    pub fn get_mut(&mut self, k: &str) -> Option<&mut T> {\n        self.inner.get_mut(k)\n    }\n\n    /// Inserts a new statement to the cache, returning the least recently used\n    /// statement id if the cache is full, or if inserting with an existing key,\n    /// the replaced existing statement.\n    pub fn insert(&mut self, k: &str, v: T) -> Option<T> {\n        let mut lru_item = None;\n\n        if self.capacity() == self.len() && !self.contains_key(k) {\n            lru_item = self.remove_lru();\n        } else if self.contains_key(k) {\n            lru_item = self.inner.remove(k);\n        }\n\n        self.inner.insert(k.into(), v);\n\n        lru_item\n    }\n\n    /// The number of statements in the cache.\n    pub fn len(&self) -> usize {\n        self.inner.len()\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.inner.is_empty()\n    }\n\n    /// Removes the least recently used item from the cache.\n    pub fn remove_lru(&mut self) -> Option<T> {\n        self.inner.remove_lru().map(|(_, v)| v)\n    }\n\n    /// Clear all cached statements from the cache.\n    pub fn clear(&mut self) {\n        self.inner.clear();\n    }\n\n    /// True if cache has a value for the given key.\n    pub fn contains_key(&mut self, k: &str) -> bool {\n        self.inner.contains_key(k)\n    }\n\n    /// Returns the maximum number of statements the cache can hold.\n    pub fn capacity(&self) -> usize {\n        self.inner.capacity()\n    }\n\n    /// Returns true if the cache capacity is more than 0.\n    #[allow(dead_code)] // Only used for some `cfg`s\n    pub fn is_enabled(&self) -> bool {\n        self.capacity() > 0\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/config/common.rs",
    "content": "/// Configuration shared by multiple components.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct Config {\n    /// Override the database URL environment variable.\n    ///\n    /// This is used by both the macros and `sqlx-cli`.\n    ///\n    /// Case-sensitive. Defaults to `DATABASE_URL`.\n    ///\n    /// Example: Multi-Database Project\n    /// -------\n    /// You can use multiple databases in the same project by breaking it up into multiple crates,\n    /// then using a different environment variable for each.\n    ///\n    /// For example, with two crates in the workspace named `foo` and `bar`:\n    ///\n    /// #### `foo/sqlx.toml`\n    /// ```toml\n    /// [common]\n    /// database-url-var = \"FOO_DATABASE_URL\"\n    /// ```\n    ///\n    /// #### `bar/sqlx.toml`\n    /// ```toml\n    /// [common]\n    /// database-url-var = \"BAR_DATABASE_URL\"\n    /// ```\n    ///\n    /// #### `.env`\n    /// ```text\n    /// FOO_DATABASE_URL=postgres://postgres@localhost:5432/foo\n    /// BAR_DATABASE_URL=postgres://postgres@localhost:5432/bar\n    /// ```\n    ///\n    /// The query macros used in `foo` will use `FOO_DATABASE_URL`,\n    /// and the ones used in `bar` will use `BAR_DATABASE_URL`.\n    pub database_url_var: Option<String>,\n}\n\nimpl Config {\n    pub fn database_url_var(&self) -> &str {\n        self.database_url_var.as_deref().unwrap_or(\"DATABASE_URL\")\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/config/drivers.rs",
    "content": "use std::error::Error;\n\n/// Configuration for specific database drivers (**applies to macros and `sqlx-cli` only**).\n///\n/// # Note: Does Not Apply at Application Run-Time\n/// As of writing, these configuration parameters do *not* have any bearing on\n/// the runtime configuration of SQLx database drivers.\n///\n/// Any parameters which overlap with runtime configuration\n/// (e.g. [`drivers.sqlite.unsafe-load-extensions`][SqliteConfig::unsafe_load_extensions])\n/// _must_ be configured their normal ways at runtime (e.g. `SqliteConnectOptions::extension()`).\n///\n/// See the documentation of individual fields for details.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct Config {\n    /// Configuration for the MySQL database driver.\n    ///\n    /// See [`MySqlConfig`] for details.\n    pub mysql: MySqlConfig,\n\n    /// Configuration for the Postgres database driver.\n    ///\n    /// See [`PgConfig`] for details.\n    pub postgres: PgConfig,\n\n    /// Configuration for the SQLite database driver.\n    ///\n    /// See [`SqliteConfig`] for details.\n    pub sqlite: SqliteConfig,\n\n    /// Configuration for external database drivers.\n    ///\n    /// See [`ExternalDriverConfig`] for details.\n    pub external: ExternalDriverConfig,\n}\n\n/// Configuration for the MySQL database driver.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct MySqlConfig {\n    // No fields implemented yet. This key is only used to validate parsing.\n}\n\n/// Configuration for the Postgres database driver.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct PgConfig {\n    // No fields implemented yet. This key is only used to validate parsing.\n}\n\n/// Configuration for the SQLite database driver.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct SqliteConfig {\n    /// Specify extensions to load, either by name or by path.\n    ///\n    /// Paths should be relative to the workspace root.\n    ///\n    /// See [Loading an Extension](https://www.sqlite.org/loadext.html#loading_an_extension)\n    /// in the SQLite manual for details.\n    ///\n    /// The `sqlite-load-extension` feature must be enabled and SQLite must be built\n    /// _without_ [`SQLITE_OMIT_LOAD_EXTENSION`] enabled.\n    ///\n    /// [`SQLITE_OMIT_LOAD_EXTENSION`]: https://www.sqlite.org/compile.html#omit_load_extension\n    ///\n    /// # Note: Does Not Configure Runtime Extension Loading\n    /// Extensions to be loaded at runtime *must* be separately configured with\n    /// `SqliteConnectOptions::extension()` or `SqliteConnectOptions::extension_with_entrypoint()`.\n    ///\n    /// # Safety\n    /// This causes arbitrary DLLs on the filesystem to be loaded at execution time,\n    /// which can easily result in undefined behavior, memory corruption,\n    /// or exploitable vulnerabilities if misused.\n    ///\n    /// It is not possible to provide a truly safe version of this API.\n    ///\n    /// Use this field with care, and only load extensions that you trust.\n    ///\n    /// # Example\n    /// Load the `uuid` and `vsv` extensions from [`sqlean`](https://github.com/nalgeon/sqlean).\n    ///\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [common.drivers.sqlite]\n    /// unsafe-load-extensions = [\"uuid\", \"vsv\"]\n    /// ```\n    pub unsafe_load_extensions: Vec<String>,\n}\n\n/// Configuration for external database drivers.\n#[derive(Debug, Default)]\n#[cfg_attr(feature = \"sqlx-toml\", derive(serde::Deserialize), serde(transparent))]\npub struct ExternalDriverConfig {\n    #[cfg(feature = \"sqlx-toml\")]\n    by_name: std::collections::BTreeMap<String, toml::Table>,\n}\n\n/// Type-erased [`toml::de::Error`].\npub type TryParseError = Box<dyn Error + Send + Sync + 'static>;\n\nimpl ExternalDriverConfig {\n    /// Try to parse the config for a given driver name, returning `Ok(None)` if it does not exist.\n    #[cfg(feature = \"sqlx-toml\")]\n    pub fn try_parse<T: serde::de::DeserializeOwned>(\n        &self,\n        name: &str,\n    ) -> Result<Option<T>, TryParseError> {\n        let Some(config) = self.by_name.get(name) else {\n            return Ok(None);\n        };\n\n        // What's really baffling is that `toml` doesn't provide any way to deserialize\n        // from a `&Table` or `&Value`, only owned variants, so cloning is unavoidable here.\n        Ok(Some(config.clone().try_into()?))\n    }\n\n    /// Try to parse the config for a given driver name, returning `Ok(None)` if it does not exist.\n    #[cfg(not(feature = \"sqlx-toml\"))]\n    pub fn try_parse<T>(&self, _name: &str) -> Result<Option<T>, TryParseError> {\n        Ok(None)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/config/macros.rs",
    "content": "use std::collections::BTreeMap;\n\n/// Configuration for the `query!()` family of macros.\n///\n/// See also [`common::Config`][crate::config::common::Config] for renaming `DATABASE_URL`.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct Config {\n    /// Specify which crates' types to use when types from multiple crates apply.\n    ///\n    /// See [`PreferredCrates`] for details.\n    pub preferred_crates: PreferredCrates,\n\n    /// Specify global overrides for mapping SQL type names to Rust type names.\n    ///\n    /// Default type mappings are defined by the database driver.\n    /// Refer to the `sqlx::types` module for details.\n    ///\n    /// ## Note: Case-Sensitive\n    /// Currently, the case of the type name MUST match the name SQLx knows it by.\n    /// Built-in types are spelled in all-uppercase to match SQL convention.\n    ///\n    /// However, user-created types in Postgres are all-lowercase unless quoted.\n    ///\n    /// ## Note: Orthogonal to Nullability\n    /// These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>`\n    /// or not. They only override the inner type used.\n    ///\n    /// ## Note: Schema Qualification (Postgres)\n    /// Type names may be schema-qualified in Postgres. If so, the schema should be part\n    /// of the type string, e.g. `'foo.bar'` to reference type `bar` in schema `foo`.\n    ///\n    /// The schema and/or type name may additionally be quoted in the string\n    /// for a quoted identifier (see next section).\n    ///\n    /// Schema qualification should not be used for types in the search path.\n    ///\n    /// ## Note: Quoted Identifiers (Postgres)\n    /// Type names using [quoted identifiers in Postgres] must also be specified with quotes here.\n    ///\n    /// Note, however, that the TOML format parses way the outer pair of quotes,\n    /// so for quoted names in Postgres, double-quoting is necessary,\n    /// e.g. `'\"Foo\"'` for SQL type `\"Foo\"`.\n    ///\n    /// To reference a schema-qualified type with a quoted name, use double-quotes after the\n    /// dot, e.g. `'foo.\"Bar\"'` to reference type `\"Bar\"` of schema `foo`, and vice versa for\n    /// quoted schema names.\n    ///\n    /// We recommend wrapping all type names in single quotes, as shown below,\n    /// to avoid confusion.\n    ///\n    /// MySQL/MariaDB and SQLite do not support custom types, so quoting type names should\n    /// never be necessary.\n    ///\n    /// [quoted identifiers in Postgres]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS\n    // Note: we wanted to be able to handle this intelligently,\n    // but the `toml` crate authors weren't interested: https://github.com/toml-rs/toml/issues/761\n    //\n    // We decided to just encourage always quoting type names instead.\n    /// Example: Custom Wrapper Types\n    /// -------\n    /// Does SQLx not support a type that you need? Do you want additional semantics not\n    /// implemented on the built-in types? You can create a custom wrapper,\n    /// or use an external crate.\n    ///\n    /// #### `sqlx.toml`\n    /// ```toml\n    /// [macros.type-overrides]\n    /// # Override a built-in type\n    /// 'UUID' = \"crate::types::MyUuid\"\n    ///\n    /// # Support an external or custom wrapper type (e.g. from the `isn` Postgres extension)\n    /// # (NOTE: FOR DOCUMENTATION PURPOSES ONLY; THIS CRATE/TYPE DOES NOT EXIST AS OF WRITING)\n    /// 'isbn13' = \"isn_rs::sqlx::ISBN13\"\n    /// ```\n    ///\n    /// Example: Custom Types in Postgres\n    /// -------\n    /// If you have a custom type in Postgres that you want to map without needing to use\n    /// the type override syntax in `sqlx::query!()` every time, you can specify a global\n    /// override here.\n    ///\n    /// For example, a custom enum type `foo`:\n    ///\n    /// #### Migration or Setup SQL (e.g. `migrations/0_setup.sql`)\n    /// ```sql\n    /// CREATE TYPE foo AS ENUM ('Bar', 'Baz');\n    /// ```\n    ///\n    /// #### `src/types.rs`\n    /// ```rust,no_run\n    /// #[derive(sqlx::Type)]\n    /// pub enum Foo {\n    ///     Bar,\n    ///     Baz\n    /// }\n    /// ```\n    ///\n    /// If you're not using `PascalCase` in your enum variants then you'll want to use\n    /// `#[sqlx(rename_all = \"<strategy>\")]` on your enum.\n    /// See [`Type`][crate::type::Type] for details.\n    ///\n    /// #### `sqlx.toml`\n    /// ```toml\n    /// [macros.type-overrides]\n    /// # Map SQL type `foo` to `crate::types::Foo`\n    /// 'foo' = \"crate::types::Foo\"\n    /// ```\n    ///\n    /// Example: Schema-Qualified Types\n    /// -------\n    /// (See `Note` section above for details.)\n    ///\n    /// ```toml\n    /// [macros.type-overrides]\n    /// # Map SQL type `foo.foo` to `crate::types::Foo`\n    /// 'foo.foo' = \"crate::types::Foo\"\n    /// ```\n    ///\n    /// Example: Quoted Identifiers\n    /// -------\n    /// If a type or schema uses quoted identifiers,\n    /// it must be wrapped in quotes _twice_ for SQLx to know the difference:\n    ///\n    /// ```toml\n    /// [macros.type-overrides]\n    /// # `\"Foo\"` in SQLx\n    /// '\"Foo\"' = \"crate::types::Foo\"\n    /// # **NOT** `\"Foo\"` in SQLx (parses as just `Foo`)\n    /// \"Foo\" = \"crate::types::Foo\"\n    ///\n    /// # Schema-qualified\n    /// '\"foo\".foo' = \"crate::types::Foo\"\n    /// 'foo.\"Foo\"' = \"crate::types::Foo\"\n    /// '\"foo\".\"Foo\"' = \"crate::types::Foo\"\n    /// ```\n    ///\n    /// (See `Note` section above for details.)\n    // TODO: allow specifying different types for input vs output\n    // e.g. to accept `&[T]` on input but output `Vec<T>`\n    pub type_overrides: BTreeMap<SqlType, RustType>,\n\n    /// Specify per-table and per-column overrides for mapping SQL types to Rust types.\n    ///\n    /// Default type mappings are defined by the database driver.\n    /// Refer to the `sqlx::types` module for details.\n    ///\n    /// The supported syntax is similar to [`type_overrides`][Self::type_overrides],\n    /// (with the same caveat for quoted names!) but column names must be qualified\n    /// by a separately quoted table name, which may optionally be schema-qualified.\n    ///\n    /// Multiple columns for the same SQL table may be written in the same table in TOML\n    /// (see examples below).\n    ///\n    /// ## Note: Orthogonal to Nullability\n    /// These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>`\n    /// or not. They only override the inner type used.\n    ///\n    /// ## Note: Schema Qualification\n    /// Table names may be schema-qualified. If so, the schema should be part\n    /// of the table name string, e.g. `'foo.bar'` to reference table `bar` in schema `foo`.\n    ///\n    /// The schema and/or type name may additionally be quoted in the string\n    /// for a quoted identifier (see next section).\n    ///\n    /// Postgres users: schema qualification should not be used for tables in the search path.\n    ///\n    /// ## Note: Quoted Identifiers\n    /// Schema, table, or column names using quoted identifiers ([MySQL], [Postgres], [SQLite])\n    /// in SQL must also be specified with quotes here.\n    ///\n    /// Postgres and SQLite use double-quotes (`\"Foo\"`) while MySQL uses backticks (`\\`Foo\\`).\n    ///\n    /// Note, however, that the TOML format parses way the outer pair of quotes,\n    /// so for quoted names in Postgres, double-quoting is necessary,\n    /// e.g. `'\"Foo\"'` for SQL name `\"Foo\"`.\n    ///\n    /// To reference a schema-qualified table with a quoted name, use the appropriate quotation\n    /// characters after the dot, e.g. `'foo.\"Bar\"'` to reference table `\"Bar\"` of schema `foo`,\n    /// and vice versa for quoted schema names.\n    ///\n    /// We recommend wrapping all table and column names in single quotes, as shown below,\n    /// to avoid confusion.\n    ///\n    /// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/identifiers.html\n    /// [Postgres]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS\n    /// [SQLite]: https://sqlite.org/lang_keywords.html\n    // Note: we wanted to be able to handle this intelligently,\n    // but the `toml` crate authors weren't interested: https://github.com/toml-rs/toml/issues/761\n    //\n    // We decided to just encourage always quoting type names instead.\n    ///\n    /// Example\n    /// -------\n    ///\n    /// #### `sqlx.toml`\n    /// ```toml\n    /// [macros.table-overrides.'foo']\n    /// # Map column `bar` of table `foo` to Rust type `crate::types::Foo`:\n    /// 'bar' = \"crate::types::Bar\"\n    ///\n    /// # Quoted column name\n    /// # Note: same quoting requirements as `macros.type_overrides`\n    /// '\"Bar\"' = \"crate::types::Bar\"\n    ///\n    /// # Note: will NOT work (parses as `Bar`)\n    /// # \"Bar\" = \"crate::types::Bar\"\n    ///\n    /// # Table name may be quoted (note the wrapping single-quotes)\n    /// [macros.table-overrides.'\"Foo\"']\n    /// 'bar' = \"crate::types::Bar\"\n    /// '\"Bar\"' = \"crate::types::Bar\"\n    ///\n    /// # Table name may also be schema-qualified.\n    /// # Note how the dot is inside the quotes.\n    /// [macros.table-overrides.'my_schema.my_table']\n    /// 'my_column' = \"crate::types::MyType\"\n    ///\n    /// # Quoted schema, table, and column names\n    /// [macros.table-overrides.'\"My Schema\".\"My Table\"']\n    /// '\"My Column\"' = \"crate::types::MyType\"\n    /// ```\n    pub table_overrides: BTreeMap<TableName, BTreeMap<ColumnName, RustType>>,\n}\n\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\")\n)]\npub struct PreferredCrates {\n    /// Specify the crate to use for mapping date/time types to Rust.\n    ///\n    /// The default behavior is to use whatever crate is enabled,\n    /// [`chrono`] or [`time`] (the latter takes precedent).\n    ///\n    /// [`chrono`]: crate::types::chrono\n    /// [`time`]: crate::types::time\n    ///\n    /// Example: Always Use Chrono\n    /// -------\n    /// Thanks to Cargo's [feature unification], a crate in the dependency graph may enable\n    /// the `time` feature of SQLx which will force it on for all crates using SQLx,\n    /// which will result in problems if your crate wants to use types from [`chrono`].\n    ///\n    /// You can use the type override syntax (see `sqlx::query!` for details),\n    /// or you can force an override globally by setting this option.\n    ///\n    /// #### `sqlx.toml`\n    /// ```toml\n    /// [macros.preferred-crates]\n    /// date-time = \"chrono\"\n    /// ```\n    ///\n    /// [feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification\n    pub date_time: DateTimeCrate,\n\n    /// Specify the crate to use for mapping `NUMERIC` types to Rust.\n    ///\n    /// The default behavior is to use whatever crate is enabled,\n    /// [`bigdecimal`] or [`rust_decimal`] (the latter takes precedent).\n    ///\n    /// [`bigdecimal`]: crate::types::bigdecimal\n    /// [`rust_decimal`]: crate::types::rust_decimal\n    ///\n    /// Example: Always Use `bigdecimal`\n    /// -------\n    /// Thanks to Cargo's [feature unification], a crate in the dependency graph may enable\n    /// the `rust_decimal` feature of SQLx which will force it on for all crates using SQLx,\n    /// which will result in problems if your crate wants to use types from [`bigdecimal`].\n    ///\n    /// You can use the type override syntax (see `sqlx::query!` for details),\n    /// or you can force an override globally by setting this option.\n    ///\n    /// #### `sqlx.toml`\n    /// ```toml\n    /// [macros.preferred-crates]\n    /// numeric = \"bigdecimal\"\n    /// ```\n    ///\n    /// [feature unification]: https://doc.rust-lang.org/cargo/reference/features.html#feature-unification\n    pub numeric: NumericCrate,\n}\n\n/// The preferred crate to use for mapping date/time types to Rust.\n#[derive(Debug, Default, PartialEq, Eq)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(rename_all = \"snake_case\")\n)]\npub enum DateTimeCrate {\n    /// Use whichever crate is enabled (`time` then `chrono`).\n    #[default]\n    Inferred,\n\n    /// Always use types from [`chrono`][crate::types::chrono].\n    ///\n    /// ```toml\n    /// [macros.preferred-crates]\n    /// date-time = \"chrono\"\n    /// ```\n    Chrono,\n\n    /// Always use types from [`time`][crate::types::time].\n    ///\n    /// ```toml\n    /// [macros.preferred-crates]\n    /// date-time = \"time\"\n    /// ```\n    Time,\n}\n\n/// The preferred crate to use for mapping `NUMERIC` types to Rust.\n#[derive(Debug, Default, PartialEq, Eq)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(rename_all = \"snake_case\")\n)]\npub enum NumericCrate {\n    /// Use whichever crate is enabled (`rust_decimal` then `bigdecimal`).\n    #[default]\n    Inferred,\n\n    /// Always use types from [`bigdecimal`][crate::types::bigdecimal].\n    ///\n    /// ```toml\n    /// [macros.preferred-crates]\n    /// numeric = \"bigdecimal\"\n    /// ```\n    #[cfg_attr(feature = \"sqlx-toml\", serde(rename = \"bigdecimal\"))]\n    BigDecimal,\n\n    /// Always use types from [`rust_decimal`][crate::types::rust_decimal].\n    ///\n    /// ```toml\n    /// [macros.preferred-crates]\n    /// numeric = \"rust_decimal\"\n    /// ```\n    RustDecimal,\n}\n\n/// A SQL type name; may optionally be schema-qualified.\n///\n/// See [`macros.type-overrides`][Config::type_overrides] for usages.\npub type SqlType = Box<str>;\n\n/// A SQL table name; may optionally be schema-qualified.\n///\n/// See [`macros.table-overrides`][Config::table_overrides] for usages.\npub type TableName = Box<str>;\n\n/// A column in a SQL table.\n///\n/// See [`macros.table-overrides`][Config::table_overrides] for usages.\npub type ColumnName = Box<str>;\n\n/// A Rust type name or path.\n///\n/// Should be a global path (not relative).\npub type RustType = Box<str>;\n\n/// Internal getter methods.\nimpl Config {\n    /// Get the override for a given type name (optionally schema-qualified).\n    pub fn type_override(&self, type_name: &str) -> Option<&str> {\n        // TODO: make this case-insensitive\n        self.type_overrides.get(type_name).map(|s| &**s)\n    }\n\n    /// Get the override for a given column and table name (optionally schema-qualified).\n    pub fn column_override(&self, table: &str, column: &str) -> Option<&str> {\n        self.table_overrides\n            .get(table)\n            .and_then(|by_column| by_column.get(column))\n            .map(|s| &**s)\n    }\n}\n\nimpl DateTimeCrate {\n    /// Returns `self == Self::Inferred`\n    #[inline(always)]\n    pub fn is_inferred(&self) -> bool {\n        *self == Self::Inferred\n    }\n\n    #[inline(always)]\n    pub fn crate_name(&self) -> Option<&str> {\n        match self {\n            Self::Inferred => None,\n            Self::Chrono => Some(\"chrono\"),\n            Self::Time => Some(\"time\"),\n        }\n    }\n}\n\nimpl NumericCrate {\n    /// Returns `self == Self::Inferred`\n    #[inline(always)]\n    pub fn is_inferred(&self) -> bool {\n        *self == Self::Inferred\n    }\n\n    #[inline(always)]\n    pub fn crate_name(&self) -> Option<&str> {\n        match self {\n            Self::Inferred => None,\n            Self::BigDecimal => Some(\"bigdecimal\"),\n            Self::RustDecimal => Some(\"rust_decimal\"),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/config/migrate.rs",
    "content": "use std::collections::BTreeSet;\n\n/// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.\n///\n/// ### Note\n/// A manually constructed [`Migrator`][crate::migrate::Migrator] will not be aware of these\n/// configuration options. We recommend using `sqlx::migrate!()` instead.\n///\n/// ### Warning: Potential Data Loss or Corruption!\n/// Many of these options, if changed after migrations are set up,\n/// can result in data loss or corruption of a production database\n/// if the proper precautions are not taken.\n///\n/// Be sure you know what you are doing and that you read all relevant documentation _thoroughly_.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct Config {\n    /// Specify the names of schemas to create if they don't already exist.\n    ///\n    /// This is done before checking the existence of the migrations table\n    /// (`_sqlx_migrations` or overridden `table_name` below) so that it may be placed in\n    /// one of these schemas.\n    ///\n    /// ### Example\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [migrate]\n    /// create-schemas = [\"foo\"]\n    /// ```\n    pub create_schemas: BTreeSet<Box<str>>,\n\n    /// Override the name of the table used to track executed migrations.\n    ///\n    /// May be schema-qualified and/or contain quotes. Defaults to `_sqlx_migrations`.\n    ///\n    /// Potentially useful for multi-tenant databases.\n    ///\n    /// ### Warning: Potential Data Loss or Corruption!\n    /// Changing this option for a production database will likely result in data loss or corruption\n    /// as the migration machinery will no longer be aware of what migrations have been applied\n    /// and will attempt to re-run them.\n    ///\n    /// You should create the new table as a copy of the existing migrations table (with contents!),\n    /// and be sure all instances of your application have been migrated to the new\n    /// table before deleting the old one.\n    ///\n    /// ### Example\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [migrate]\n    /// # Put `_sqlx_migrations` in schema `foo`\n    /// table-name = \"foo._sqlx_migrations\"\n    /// ```\n    pub table_name: Option<Box<str>>,\n\n    /// Override the directory used for migrations files.\n    ///\n    /// Relative to the crate root for `sqlx::migrate!()`, or the current directory for `sqlx-cli`.\n    pub migrations_dir: Option<Box<str>>,\n\n    /// Specify characters that should be ignored when hashing migrations.\n    ///\n    /// Any characters contained in the given array will be dropped when a migration is hashed.\n    ///\n    /// ### Warning: May Change Hashes for Existing Migrations\n    /// Changing the characters considered in hashing migrations will likely\n    /// change the output of the hash.\n    ///\n    /// This may require manual rectification for deployed databases.\n    ///\n    /// ### Example: Ignore Carriage Return (`<CR>` | `\\r`)\n    /// Line ending differences between platforms can result in migrations having non-repeatable\n    /// hashes. The most common culprit is the carriage return (`<CR>` | `\\r`), which Windows\n    /// uses in its line endings alongside line feed (`<LF>` | `\\n`), often written `CRLF` or `\\r\\n`,\n    /// whereas Linux and macOS use only line feeds.\n    ///\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [migrate]\n    /// ignored-chars = [\"\\r\"]\n    /// ```\n    ///\n    /// For projects using Git, this can also be addressed using [`.gitattributes`]:\n    ///\n    /// ```text\n    /// # Force newlines in migrations to be line feeds on all platforms\n    /// migrations/*.sql text eol=lf\n    /// ```\n    ///\n    /// This may require resetting or re-checking out the migrations files to take effect.\n    ///\n    /// [`.gitattributes`]: https://git-scm.com/docs/gitattributes\n    ///\n    /// ### Example: Ignore all Whitespace Characters\n    /// To make your migrations amenable to reformatting, you may wish to tell SQLx to ignore\n    /// _all_ whitespace characters in migrations.\n    ///\n    /// ##### Warning: Beware Syntactically Significant Whitespace!\n    /// If your migrations use string literals or quoted identifiers which contain whitespace,\n    /// this configuration will cause the migration machinery to ignore some changes to these.\n    /// This may result in a mismatch between the development and production versions of\n    /// your database.\n    ///\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [migrate]\n    /// # Ignore common whitespace characters when hashing\n    /// ignored-chars = [\" \", \"\\t\", \"\\r\", \"\\n\"]  # Space, tab, CR, LF\n    /// ```\n    // Likely lower overhead for small sets than `HashSet`.\n    pub ignored_chars: BTreeSet<char>,\n\n    /// Specify default options for new migrations created with `sqlx migrate add`.\n    pub defaults: MigrationDefaults,\n}\n\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\")\n)]\npub struct MigrationDefaults {\n    /// Specify the default type of migration that `sqlx migrate add` should create by default.\n    ///\n    /// ### Example: Use Reversible Migrations by Default\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [migrate.defaults]\n    /// migration-type = \"reversible\"\n    /// ```\n    pub migration_type: DefaultMigrationType,\n\n    /// Specify the default scheme that `sqlx migrate add` should use for version integers.\n    ///\n    /// ### Example: Use Sequential Versioning by Default\n    /// `sqlx.toml`:\n    /// ```toml\n    /// [migrate.defaults]\n    /// migration-versioning = \"sequential\"\n    /// ```\n    pub migration_versioning: DefaultVersioning,\n}\n\n/// The default type of migration that `sqlx migrate add` should create by default.\n#[derive(Debug, Default, PartialEq, Eq)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(rename_all = \"snake_case\")\n)]\npub enum DefaultMigrationType {\n    /// Create the same migration type as that of the latest existing migration,\n    /// or `Simple` otherwise.\n    #[default]\n    Inferred,\n\n    /// Create non-reversible migrations (`<VERSION>_<DESCRIPTION>.sql`) by default.\n    Simple,\n\n    /// Create reversible migrations (`<VERSION>_<DESCRIPTION>.up.sql` and `[...].down.sql`) by default.\n    Reversible,\n}\n\n/// The default scheme that `sqlx migrate add` should use for version integers.\n#[derive(Debug, Default, PartialEq, Eq)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(rename_all = \"snake_case\")\n)]\npub enum DefaultVersioning {\n    /// Infer the versioning scheme from existing migrations:\n    ///\n    /// * If the versions of the last two migrations differ by `1`, infer `Sequential`.\n    /// * If only one migration exists and has version `1`, infer `Sequential`.\n    /// * Otherwise, infer `Timestamp`.\n    #[default]\n    Inferred,\n\n    /// Use UTC timestamps for migration versions.\n    ///\n    /// This is the recommended versioning format as it's less likely to collide when multiple\n    /// developers are creating migrations on different branches.\n    ///\n    /// The exact timestamp format is unspecified.\n    Timestamp,\n\n    /// Use sequential integers for migration versions.\n    Sequential,\n}\n\n#[cfg(feature = \"migrate\")]\nimpl Config {\n    pub fn migrations_dir(&self) -> &str {\n        self.migrations_dir.as_deref().unwrap_or(\"migrations\")\n    }\n\n    pub fn table_name(&self) -> &str {\n        self.table_name.as_deref().unwrap_or(\"_sqlx_migrations\")\n    }\n\n    pub fn to_resolve_config(&self) -> crate::migrate::ResolveConfig {\n        let mut config = crate::migrate::ResolveConfig::new();\n        config.ignore_chars(self.ignored_chars.iter().copied());\n        config\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/config/mod.rs",
    "content": "//! (Exported for documentation only) Guide and reference for `sqlx.toml` files.\n//!\n//! To use, create a `sqlx.toml` file in your crate root (the same directory as your `Cargo.toml`).\n//! The configuration in a `sqlx.toml` configures SQLx *only* for the current crate.\n//!\n//! Requires the `sqlx-toml` feature (not enabled by default).\n//!\n//! `sqlx-cli` will also read `sqlx.toml` when running migrations.\n//!\n//! See the [`Config`] type and its fields for individual configuration options.\n//!\n//! See the [reference][`_reference`] for the full `sqlx.toml` file.\n\nuse std::error::Error;\nuse std::fmt::Debug;\nuse std::io;\nuse std::path::{Path, PathBuf};\n\n/// Configuration shared by multiple components.\n///\n/// See [`common::Config`] for details.\npub mod common;\n\npub mod drivers;\n\n/// Configuration for the `query!()` family of macros.\n///\n/// See [`macros::Config`] for details.\npub mod macros;\n\n/// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.\n///\n/// See [`migrate::Config`] for details.\npub mod migrate;\n\n/// Reference for `sqlx.toml` files\n///\n/// Source: `sqlx-core/src/config/reference.toml`\n///\n/// ```toml\n#[doc = include_str!(\"reference.toml\")]\n/// ```\npub mod _reference {}\n\n#[cfg(all(test, feature = \"sqlx-toml\"))]\nmod tests;\n\n/// The parsed structure of a `sqlx.toml` file.\n#[derive(Debug, Default)]\n#[cfg_attr(\n    feature = \"sqlx-toml\",\n    derive(serde::Deserialize),\n    serde(default, rename_all = \"kebab-case\", deny_unknown_fields)\n)]\npub struct Config {\n    /// Configuration shared by multiple components.\n    ///\n    /// See [`common::Config`] for details.\n    pub common: common::Config,\n\n    /// Configuration for database drivers.\n    ///\n    /// See [`drivers::Config`] for details.\n    pub drivers: drivers::Config,\n\n    /// Configuration for the `query!()` family of macros.\n    ///\n    /// See [`macros::Config`] for details.\n    pub macros: macros::Config,\n\n    /// Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.\n    ///\n    /// See [`migrate::Config`] for details.\n    pub migrate: migrate::Config,\n}\n\n/// Error returned from various methods of [`Config`].\n#[derive(thiserror::Error, Debug)]\npub enum ConfigError {\n    /// The loading method expected `CARGO_MANIFEST_DIR` to be set and it wasn't.\n    ///\n    /// This is necessary to locate the root of the crate currently being compiled.\n    ///\n    /// See [the \"Environment Variables\" page of the Cargo Book][cargo-env] for details.\n    ///\n    /// [cargo-env]: https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates\n    #[error(\"environment variable `CARGO_MANIFEST_DIR` must be set and valid\")]\n    Env(\n        #[from]\n        #[source]\n        std::env::VarError,\n    ),\n\n    /// No configuration file was found. Not necessarily fatal.\n    #[error(\"config file {path:?} not found\")]\n    NotFound { path: PathBuf },\n\n    /// An I/O error occurred while attempting to read the config file at `path`.\n    ///\n    /// If the error is [`io::ErrorKind::NotFound`], [`Self::NotFound`] is returned instead.\n    #[error(\"error reading config file {path:?}\")]\n    Io {\n        path: PathBuf,\n        #[source]\n        error: io::Error,\n    },\n\n    /// An error in the TOML was encountered while parsing the config file at `path`.\n    ///\n    /// The error gives line numbers and context when printed with `Display`/`ToString`.\n    ///\n    /// Only returned if the `sqlx-toml` feature is enabled.\n    #[error(\"error parsing config file {path:?}\")]\n    Parse {\n        path: PathBuf,\n        /// Type-erased [`toml::de::Error`].\n        #[source]\n        error: Box<dyn Error + Send + Sync + 'static>,\n    },\n\n    /// A `sqlx.toml` file was found or specified, but the `sqlx-toml` feature is not enabled.\n    #[error(\"SQLx found config file at {path:?} but the `sqlx-toml` feature was not enabled\")]\n    ParseDisabled { path: PathBuf },\n}\n\nimpl ConfigError {\n    /// Create a [`ConfigError`] from a [`std::io::Error`].\n    ///\n    /// Maps to either `NotFound` or `Io`.\n    pub fn from_io(path: impl Into<PathBuf>, error: io::Error) -> Self {\n        if error.kind() == io::ErrorKind::NotFound {\n            Self::NotFound { path: path.into() }\n        } else {\n            Self::Io {\n                path: path.into(),\n                error,\n            }\n        }\n    }\n\n    /// If this error means the file was not found, return the path that was attempted.\n    pub fn not_found_path(&self) -> Option<&Path> {\n        if let Self::NotFound { path } = self {\n            Some(path)\n        } else {\n            None\n        }\n    }\n}\n\n/// Internal methods for loading a `Config`.\n#[allow(clippy::result_large_err)]\nimpl Config {\n    /// Read `$CARGO_MANIFEST_DIR/sqlx.toml` or return `Config::default()` if it does not exist.\n    ///\n    /// # Errors\n    /// * If `CARGO_MANIFEST_DIR` is not set.\n    /// * If the file exists but could not be read or parsed.\n    /// * If the file exists but the `sqlx-toml` feature is disabled.\n    pub fn try_from_crate_or_default() -> Result<Self, ConfigError> {\n        Self::try_from_path_or_default(get_crate_path()?)\n    }\n\n    /// Attempt to read `Config` from the path given, or return `Config::default()` if it does not exist.\n    ///\n    /// # Errors\n    /// * If the file exists but could not be read or parsed.\n    /// * If the file exists but the `sqlx-toml` feature is disabled.\n    pub fn try_from_path_or_default(path: PathBuf) -> Result<Self, ConfigError> {\n        Self::read_from(path).or_else(|e| {\n            if let ConfigError::NotFound { .. } = e {\n                Ok(Config::default())\n            } else {\n                Err(e)\n            }\n        })\n    }\n\n    /// Attempt to read `Config` from the path given.\n    ///\n    /// # Errors\n    /// * If the file does not exist.\n    /// * If the file exists but could not be read or parsed.\n    /// * If the file exists but the `sqlx-toml` feature is disabled.\n    pub fn try_from_path(path: PathBuf) -> Result<Self, ConfigError> {\n        Self::read_from(path)\n    }\n\n    #[cfg(feature = \"sqlx-toml\")]\n    fn read_from(path: PathBuf) -> Result<Self, ConfigError> {\n        // The `toml` crate doesn't provide an incremental reader.\n        let toml_s = match std::fs::read_to_string(&path) {\n            Ok(toml) => toml,\n            Err(error) => {\n                return Err(ConfigError::from_io(path, error));\n            }\n        };\n\n        // TODO: parse and lint TOML structure before deserializing\n        // Motivation: https://github.com/toml-rs/toml/issues/761\n        tracing::debug!(\"read config TOML from {path:?}:\\n{toml_s}\");\n\n        toml::from_str(&toml_s).map_err(|error| ConfigError::Parse {\n            path,\n            error: Box::new(error),\n        })\n    }\n\n    #[cfg(not(feature = \"sqlx-toml\"))]\n    fn read_from(path: PathBuf) -> Result<Self, ConfigError> {\n        match path.try_exists() {\n            Ok(true) => Err(ConfigError::ParseDisabled { path }),\n            Ok(false) => Err(ConfigError::NotFound { path }),\n            Err(e) => Err(ConfigError::from_io(path, e)),\n        }\n    }\n}\n\nfn get_crate_path() -> Result<PathBuf, ConfigError> {\n    let mut path = PathBuf::from(std::env::var(\"CARGO_MANIFEST_DIR\")?);\n    path.push(\"sqlx.toml\");\n    Ok(path)\n}\n"
  },
  {
    "path": "sqlx-core/src/config/reference.toml",
    "content": "# `sqlx.toml` reference.\n#\n# Note: shown values are *not* defaults.\n# They are explicitly set to non-default values to test parsing.\n# Refer to the comment for a given option for its default value.\n\n###############################################################################################\n\n# Configuration shared by multiple components.\n[common]\n# Change the environment variable to get the database URL.\n#\n# This is used by both the macros and `sqlx-cli`.\n#\n# If not specified, defaults to `DATABASE_URL`\ndatabase-url-var = \"FOO_DATABASE_URL\"\n\n###############################################################################################\n\n# Configuration of SQLx database drivers (**applies to macros and sqlx-cli only**)\n[drivers]\n\n# Configure MySQL databases in macros and sqlx-cli.\n[drivers.mysql]\n# No fields implemented yet. This key is only used to validate parsing.\n\n# Configure Postgres databases in macros and sqlx-cli.\n[drivers.postgres]\n# No fields implemented yet. This key is only used to validate parsing.\n\n# Configure Postgres databases in macros and sqlx-cli.\n[drivers.sqlite]\n# Load extensions into SQLite when running macros or migrations\n#\n# Defaults to an empty list, which has no effect.\n#\n# Must be specified separately at run-time using `SqliteConnectOptions::extension()` or `::extension_with_entrypoint()`.\n#\n# Safety\n# This causes arbitrary DLLs on the filesystem to be loaded at runtime,\n# which can easily result in undefined behavior, memory corruption,\n# or exploitable vulnerabilities if misused.\n#\n# It is not possible to provide a truly safe version of this API.\n#\n# Use this field with care, and only load extensions that you trust.\nunsafe-load-extensions = [\"uuid\", \"vsv\"]\n\n# Configure external drivers in macros and sqlx-cli.\n#\n# These keys are only validated when the external driver tries to parse them,\n# unlike config for built-in drivers which is validated directly.\n[drivers.external.\"<external driver name>\"]\nfoo = 'foo'\nbar = true\n\n###############################################################################################\n\n# Configuration for the `query!()` family of macros.\n[macros]\n\n[macros.preferred-crates]\n# Force the macros to use the `chrono` crate for date/time types, even if `time` is enabled.\n#\n# Defaults to \"inferred\": use whichever crate is enabled (`time` takes precedence over `chrono`).\ndate-time = \"chrono\"\n\n# Or, ensure the macros always prefer `time`\n# in case new date/time crates are added in the future:\n# date-time = \"time\"\n\n# Force the macros to use the `rust_decimal` crate for `NUMERIC`, even if `bigdecimal` is enabled.\n#\n# Defaults to \"inferred\": use whichever crate is enabled (`bigdecimal` takes precedence over `rust_decimal`).\nnumeric = \"rust_decimal\"\n\n# Or, ensure the macros always prefer `bigdecimal`\n# in case new decimal crates are added in the future:\n# numeric = \"bigdecimal\"\n\n# Set global overrides for mapping SQL types to Rust types.\n#\n# Default type mappings are defined by the database driver.\n# Refer to the `sqlx::types` module for details.\n#\n# Postgres users: schema qualification should not be used for types in the search path.\n#\n# ### Note: Orthogonal to Nullability\n# These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>`\n# or not. They only override the inner type used.\n[macros.type-overrides]\n# Override a built-in type (map all `UUID` columns to `crate::types::MyUuid`)\n# Note: currently, the case of the type name MUST match. \n# Built-in types are spelled in all-uppercase to match SQL convention. \n'UUID' = \"crate::types::MyUuid\"\n\n# Support an external or custom wrapper type (e.g. from the `isn` Postgres extension)\n# (NOTE: FOR DOCUMENTATION PURPOSES ONLY; THIS CRATE/TYPE DOES NOT EXIST AS OF WRITING)\n'isbn13' = \"isn_rs::isbn::ISBN13\"\n\n# SQL type `foo` to Rust type `crate::types::Foo`:\n'foo' = \"crate::types::Foo\"\n\n# SQL type `\"Bar\"` to Rust type `crate::types::Bar`; notice the extra pair of quotes:\n'\"Bar\"' = \"crate::types::Bar\"\n\n# Will NOT work (the first pair of quotes are parsed by TOML)\n# \"Bar\" = \"crate::types::Bar\"\n\n# Schema qualified\n'foo.bar' = \"crate::types::Bar\"\n\n# Schema qualified and quoted\n'foo.\"Bar\"' = \"crate::schema::foo::Bar\"\n\n# Quoted schema name\n'\"Foo\".bar' = \"crate::schema::foo::Bar\"\n\n# Quoted schema and type name\n'\"Foo\".\"Bar\"' = \"crate::schema::foo::Bar\"\n\n# Set per-table and per-column overrides for mapping SQL types to Rust types.\n#\n# Note: table name is required in the header.\n#\n# Postgres users: schema qualification should not be used for types in the search path.\n#\n# ### Note: Orthogonal to Nullability\n# These overrides do not affect whether `query!()` decides to wrap a column in `Option<_>`\n# or not. They only override the inner type used.\n[macros.table-overrides.'foo']\n# Map column `bar` of table `foo` to Rust type `crate::types::Foo`:\n'bar' = \"crate::types::Bar\"\n\n# Quoted column name\n# Note: same quoting requirements as `macros.type_overrides`\n'\"Bar\"' = \"crate::types::Bar\"\n\n# Note: will NOT work (parses as `Bar`)\n# \"Bar\" = \"crate::types::Bar\"\n\n# Table name may be quoted (note the wrapping single-quotes)\n[macros.table-overrides.'\"Foo\"']\n'bar' = \"crate::types::Bar\"\n'\"Bar\"' = \"crate::types::Bar\"\n\n# Table name may also be schema-qualified.\n# Note how the dot is inside the quotes.\n[macros.table-overrides.'my_schema.my_table']\n'my_column' = \"crate::types::MyType\"\n\n# Quoted schema, table, and column names\n[macros.table-overrides.'\"My Schema\".\"My Table\"']\n'\"My Column\"' = \"crate::types::MyType\"\n\n###############################################################################################\n\n# Configuration for migrations when executed using `sqlx::migrate!()` or through `sqlx-cli`.\n#\n# ### Note\n# A manually constructed [`Migrator`][crate::migrate::Migrator] will not be aware of these\n# configuration options. We recommend using `sqlx::migrate!()` instead.\n#\n# ### Warning: Potential Data Loss or Corruption!\n# Many of these options, if changed after migrations are set up,\n# can result in data loss or corruption of a production database\n# if the proper precautions are not taken.\n#\n# Be sure you know what you are doing and that you read all relevant documentation _thoroughly_.\n[migrate]\n# Override the name of the table used to track executed migrations.\n#\n# May be schema-qualified and/or contain quotes. Defaults to `_sqlx_migrations`.\n#\n# Potentially useful for multi-tenant databases.\n#\n# ### Warning: Potential Data Loss or Corruption!\n# Changing this option for a production database will likely result in data loss or corruption\n# as the migration machinery will no longer be aware of what migrations have been applied\n# and will attempt to re-run them.\n#\n# You should create the new table as a copy of the existing migrations table (with contents!),\n# and be sure all instances of your application have been migrated to the new\n# table before deleting the old one.\ntable-name = \"foo._sqlx_migrations\"\n\n# Override the directory used for migrations files.\n#\n# Relative to the crate root for `sqlx::migrate!()`, or the current directory for `sqlx-cli`.\nmigrations-dir = \"foo/migrations\"\n\n# Specify characters that should be ignored when hashing migrations.\n#\n# Any characters contained in the given set will be dropped when a migration is hashed.\n#\n# Defaults to an empty array (don't drop any characters).\n#\n# ### Warning: May Change Hashes for Existing Migrations\n# Changing the characters considered in hashing migrations will likely\n# change the output of the hash.\n#\n# This may require manual rectification for deployed databases.\n# ignored-chars = []\n\n# Ignore Carriage Returns (`<CR>` | `\\r`)\n# Note that the TOML format requires double-quoted strings to process escapes.\n# ignored-chars = [\"\\r\"]\n\n# Ignore common whitespace characters (beware syntactically significant whitespace!)\n# Space, tab, CR, LF, zero-width non-breaking space (U+FEFF)\n#\n# U+FEFF is added by some editors as a magic number at the beginning of a text file indicating it is UTF-8 encoded,\n# where it is known as a byte-order mark (BOM): https://en.wikipedia.org/wiki/Byte_order_mark\nignored-chars = [\" \", \"\\t\", \"\\r\", \"\\n\", \"\\uFEFF\"]\n\n# Set default options for new migrations.\n[migrate.defaults]\n# Specify reversible migrations by default (for `sqlx migrate create`).\n#\n# Defaults to \"inferred\": uses the type of the last migration, or \"simple\" otherwise.\nmigration-type = \"reversible\"\n\n# Specify simple (non-reversible) migrations by default.\n# migration-type = \"simple\"\n\n# Specify sequential versioning by default (for `sqlx migrate create`).\n#\n# Defaults to \"inferred\": guesses the versioning scheme from the latest migrations,\n# or \"timestamp\" otherwise.\nmigration-versioning = \"sequential\"\n\n# Specify timestamp versioning by default.\n# migration-versioning = \"timestamp\"\n"
  },
  {
    "path": "sqlx-core/src/config/tests.rs",
    "content": "use crate::config::{self, Config};\nuse std::collections::BTreeSet;\n\n#[test]\nfn reference_parses_as_config() {\n    let config: Config = toml::from_str(include_str!(\"reference.toml\"))\n        // The `Display` impl of `toml::Error` is *actually* more useful than `Debug`\n        .unwrap_or_else(|e| panic!(\"expected reference.toml to parse as Config: {e}\"));\n\n    assert_common_config(&config.common);\n    assert_drivers_config(&config.drivers);\n    assert_macros_config(&config.macros);\n    assert_migrate_config(&config.migrate);\n}\n\nfn assert_common_config(config: &config::common::Config) {\n    assert_eq!(config.database_url_var.as_deref(), Some(\"FOO_DATABASE_URL\"));\n}\n\nfn assert_drivers_config(config: &config::drivers::Config) {\n    assert_eq!(config.sqlite.unsafe_load_extensions, [\"uuid\", \"vsv\"]);\n\n    #[derive(Debug, Eq, PartialEq, serde::Deserialize)]\n    #[serde(rename_all = \"kebab-case\")]\n    struct TestExternalDriverConfig {\n        foo: String,\n        bar: bool,\n    }\n\n    assert_eq!(\n        config.external.try_parse(\"<external driver name>\").unwrap(),\n        Some(TestExternalDriverConfig {\n            foo: \"foo\".to_string(),\n            bar: true\n        })\n    );\n}\n\nfn assert_macros_config(config: &config::macros::Config) {\n    use config::macros::*;\n\n    assert_eq!(config.preferred_crates.date_time, DateTimeCrate::Chrono);\n    assert_eq!(config.preferred_crates.numeric, NumericCrate::RustDecimal);\n\n    // Type overrides\n    // Don't need to cover everything, just some important canaries.\n    assert_eq!(config.type_override(\"UUID\"), Some(\"crate::types::MyUuid\"));\n\n    assert_eq!(config.type_override(\"foo\"), Some(\"crate::types::Foo\"));\n\n    assert_eq!(config.type_override(r#\"\"Bar\"\"#), Some(\"crate::types::Bar\"),);\n\n    assert_eq!(\n        config.type_override(r#\"\"Foo\".bar\"#),\n        Some(\"crate::schema::foo::Bar\"),\n    );\n\n    assert_eq!(\n        config.type_override(r#\"\"Foo\".\"Bar\"\"#),\n        Some(\"crate::schema::foo::Bar\"),\n    );\n\n    // Column overrides\n    assert_eq!(\n        config.column_override(\"foo\", \"bar\"),\n        Some(\"crate::types::Bar\"),\n    );\n\n    assert_eq!(\n        config.column_override(\"foo\", r#\"\"Bar\"\"#),\n        Some(\"crate::types::Bar\"),\n    );\n\n    assert_eq!(\n        config.column_override(r#\"\"Foo\"\"#, \"bar\"),\n        Some(\"crate::types::Bar\"),\n    );\n\n    assert_eq!(\n        config.column_override(r#\"\"Foo\"\"#, r#\"\"Bar\"\"#),\n        Some(\"crate::types::Bar\"),\n    );\n\n    assert_eq!(\n        config.column_override(\"my_schema.my_table\", \"my_column\"),\n        Some(\"crate::types::MyType\"),\n    );\n\n    assert_eq!(\n        config.column_override(r#\"\"My Schema\".\"My Table\"\"#, r#\"\"My Column\"\"#),\n        Some(\"crate::types::MyType\"),\n    );\n}\n\nfn assert_migrate_config(config: &config::migrate::Config) {\n    use config::migrate::*;\n\n    assert_eq!(config.table_name.as_deref(), Some(\"foo._sqlx_migrations\"));\n    assert_eq!(config.migrations_dir.as_deref(), Some(\"foo/migrations\"));\n\n    let ignored_chars = BTreeSet::from([' ', '\\t', '\\r', '\\n', '\\u{FEFF}']);\n\n    assert_eq!(config.ignored_chars, ignored_chars);\n\n    assert_eq!(\n        config.defaults.migration_type,\n        DefaultMigrationType::Reversible\n    );\n    assert_eq!(\n        config.defaults.migration_versioning,\n        DefaultVersioning::Sequential\n    );\n}\n"
  },
  {
    "path": "sqlx-core/src/connection.rs",
    "content": "use crate::database::{Database, HasStatementCache};\nuse crate::error::Error;\n\nuse crate::config;\nuse crate::sql_str::SqlSafeStr;\nuse crate::transaction::{Transaction, TransactionManager};\nuse futures_core::future::BoxFuture;\nuse log::LevelFilter;\nuse std::fmt::Debug;\nuse std::future::Future;\nuse std::str::FromStr;\nuse std::time::Duration;\nuse url::Url;\n\n/// Represents a single database connection.\npub trait Connection: Send {\n    type Database: Database<Connection = Self>;\n\n    type Options: ConnectOptions<Connection = Self>;\n\n    /// Explicitly close this database connection.\n    ///\n    /// This notifies the database server that the connection is closing so that it can\n    /// free up any server-side resources in use.\n    ///\n    /// While connections can simply be dropped to clean up local resources,\n    /// the `Drop` handler itself cannot notify the server that the connection is being closed\n    /// because that may require I/O to send a termination message. That can result in a delay\n    /// before the server learns that the connection is gone, usually from a TCP keepalive timeout.\n    ///\n    /// Creating and dropping many connections in short order without calling `.close()` may\n    /// lead to errors from the database server because those senescent connections will still\n    /// count against any connection limit or quota that is configured.\n    ///\n    /// Therefore it is recommended to call `.close()` on a connection when you are done using it\n    /// and to `.await` the result to ensure the termination message is sent.\n    fn close(self) -> impl Future<Output = Result<(), Error>> + Send + 'static;\n\n    /// Immediately close the connection without sending a graceful shutdown.\n    ///\n    /// This should still at least send a TCP `FIN` frame to let the server know we're dying.\n    #[doc(hidden)]\n    fn close_hard(self) -> impl Future<Output = Result<(), Error>> + Send + 'static;\n\n    /// Checks if a connection to the database is still valid.\n    fn ping(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    /// Begin a new transaction or establish a savepoint within the active transaction.\n    ///\n    /// Returns a [`Transaction`] for controlling and tracking the new transaction.\n    fn begin(\n        &mut self,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_;\n\n    /// Begin a new transaction with a custom statement.\n    ///\n    /// Returns a [`Transaction`] for controlling and tracking the new transaction.\n    ///\n    /// Returns an error if the connection is already in a transaction or if\n    /// `statement` does not put the connection into a transaction.\n    fn begin_with(\n        &mut self,\n        statement: impl SqlSafeStr,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        Transaction::begin(self, Some(statement.into_sql_str()))\n    }\n\n    /// Returns `true` if the connection is currently in a transaction.\n    ///\n    /// # Note: Automatic Rollbacks May Not Be Counted\n    /// Certain database errors (such as a serializable isolation failure)\n    /// can cause automatic rollbacks of a transaction\n    /// which may not be indicated in the return value of this method.\n    #[inline]\n    fn is_in_transaction(&self) -> bool {\n        <Self::Database as Database>::TransactionManager::get_transaction_depth(self) != 0\n    }\n\n    /// Execute the function inside a transaction.\n    ///\n    /// If the function returns an error, the transaction will be rolled back. If it does not\n    /// return an error, the transaction will be committed.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// use sqlx::postgres::{PgConnection, PgRow};\n    /// use sqlx::Connection;\n    ///\n    /// # pub async fn _f(conn: &mut PgConnection) -> sqlx::Result<Vec<PgRow>> {\n    /// conn.transaction(|txn| Box::pin(async move {\n    ///     sqlx::query(\"select * from ..\").fetch_all(&mut **txn).await\n    /// })).await\n    /// # }\n    /// ```\n    fn transaction<'a, F, R, E>(\n        &'a mut self,\n        callback: F,\n    ) -> impl Future<Output = Result<R, E>> + Send + 'a\n    where\n        for<'c> F: FnOnce(&'c mut Transaction<'_, Self::Database>) -> BoxFuture<'c, Result<R, E>>\n            + 'a\n            + Send\n            + Sync,\n        Self: Sized,\n        R: Send,\n        E: From<Error> + Send,\n    {\n        async move {\n            let mut transaction = self.begin().await?;\n            let ret = callback(&mut transaction).await;\n\n            match ret {\n                Ok(ret) => {\n                    transaction.commit().await?;\n\n                    Ok(ret)\n                }\n                Err(err) => {\n                    transaction.rollback().await?;\n\n                    Err(err)\n                }\n            }\n        }\n    }\n\n    /// The number of statements currently cached in the connection.\n    fn cached_statements_size(&self) -> usize\n    where\n        Self::Database: HasStatementCache,\n    {\n        0\n    }\n\n    /// Removes all statements from the cache, closing them on the server if\n    /// needed.\n    fn clear_cached_statements(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_\n    where\n        Self::Database: HasStatementCache,\n    {\n        async move { Ok(()) }\n    }\n\n    /// Restore any buffers in the connection to their default capacity, if possible.\n    ///\n    /// Sending a large query or receiving a resultset with many columns can cause the connection\n    /// to allocate additional buffer space to fit the data which is retained afterwards in\n    /// case it's needed again. This can give the outward appearance of a memory leak, but is\n    /// in fact the intended behavior.\n    ///\n    /// Calling this method tells the connection to release that excess memory if it can,\n    /// though be aware that calling this too often can cause unnecessary thrashing or\n    /// fragmentation in the global allocator. If there's still data in the connection buffers\n    /// (unlikely if the last query was run to completion) then it may need to be moved to\n    /// allow the buffers to shrink.\n    fn shrink_buffers(&mut self);\n\n    #[doc(hidden)]\n    fn flush(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    #[doc(hidden)]\n    fn should_flush(&self) -> bool;\n\n    /// Establish a new database connection.\n    ///\n    /// A value of [`Options`][Self::Options] is parsed from the provided connection string. This parsing\n    /// is database-specific.\n    #[inline]\n    fn connect(url: &str) -> impl Future<Output = Result<Self, Error>> + Send + 'static\n    where\n        Self: Sized,\n    {\n        let options = url.parse();\n\n        async move { Self::connect_with(&options?).await }\n    }\n\n    /// Establish a new database connection with the provided options.\n    fn connect_with(\n        options: &Self::Options,\n    ) -> impl Future<Output = Result<Self, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        options.connect()\n    }\n}\n\n#[derive(Clone, Debug)]\n#[non_exhaustive]\npub struct LogSettings {\n    pub statements_level: LevelFilter,\n    pub slow_statements_level: LevelFilter,\n    pub slow_statements_duration: Duration,\n}\n\nimpl Default for LogSettings {\n    fn default() -> Self {\n        LogSettings {\n            statements_level: LevelFilter::Debug,\n            slow_statements_level: LevelFilter::Warn,\n            slow_statements_duration: Duration::from_secs(1),\n        }\n    }\n}\n\nimpl LogSettings {\n    pub fn log_statements(&mut self, level: LevelFilter) {\n        self.statements_level = level;\n    }\n    pub fn log_slow_statements(&mut self, level: LevelFilter, duration: Duration) {\n        self.slow_statements_level = level;\n        self.slow_statements_duration = duration;\n    }\n}\n\npub trait ConnectOptions: 'static + Send + Sync + FromStr<Err = Error> + Debug + Clone {\n    type Connection: Connection<Options = Self> + ?Sized;\n\n    /// Parse the `ConnectOptions` from a URL.\n    fn from_url(url: &Url) -> Result<Self, Error>;\n\n    /// Get a connection URL that may be used to connect to the same database as this `ConnectOptions`.\n    ///\n    /// ### Note: Lossy\n    /// Any flags or settings which do not have a representation in the URL format will be lost.\n    /// They will fall back to their default settings when the URL is parsed.\n    ///\n    /// The only settings guaranteed to be preserved are:\n    /// * Username\n    /// * Password\n    /// * Hostname\n    /// * Port\n    /// * Database name\n    /// * Unix socket or SQLite database file path\n    /// * SSL mode (if applicable)\n    /// * SSL CA certificate path\n    /// * SSL client certificate path\n    /// * SSL client key path\n    ///\n    /// Additional settings are driver-specific. Refer to the source of a given implementation\n    /// to see which options are preserved in the URL.\n    ///\n    /// ### Panics\n    /// This defaults to `unimplemented!()`.\n    ///\n    /// Individual drivers should override this to implement the intended behavior.\n    fn to_url_lossy(&self) -> Url {\n        unimplemented!()\n    }\n\n    /// Establish a new database connection with the options specified by `self`.\n    fn connect(&self) -> impl Future<Output = Result<Self::Connection, Error>> + Send + '_\n    where\n        Self::Connection: Sized;\n\n    /// Log executed statements with the specified `level`\n    fn log_statements(self, level: LevelFilter) -> Self;\n\n    /// Log executed statements with a duration above the specified `duration`\n    /// at the specified `level`.\n    fn log_slow_statements(self, level: LevelFilter, duration: Duration) -> Self;\n\n    /// Entirely disables statement logging (both slow and regular).\n    fn disable_statement_logging(self) -> Self {\n        self.log_statements(LevelFilter::Off)\n            .log_slow_statements(LevelFilter::Off, Duration::default())\n    }\n\n    #[doc(hidden)]\n    fn __unstable_apply_driver_config(\n        self,\n        _config: &config::drivers::Config,\n    ) -> crate::Result<Self> {\n        Ok(self)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/database.rs",
    "content": "//! Traits to represent a database driver.\n//!\n//! # Support\n//!\n//! ## Tier 1\n//!\n//! Tier 1 support can be thought of as \"guaranteed to work\". Automated testing is setup to\n//! ensure a high level of stability and functionality.\n//!\n//! | Database | Version | Driver |\n//! | - | - | - |\n//! | [MariaDB] | 10.1+ | [`mysql`] |\n//! | [Microsoft SQL Server] | 2019 | [`mssql`] (Pending a full rewrite) |\n//! | [MySQL] | 5.6, 5.7, 8.0 | [`mysql`] |\n//! | [PostgreSQL] | 13+ | [`postgres`] |\n//! | [SQLite] | 3.20.1+ | [`sqlite`] |\n//!\n//! [MariaDB]: https://mariadb.com/\n//! [MySQL]: https://www.mysql.com/\n//! [Microsoft SQL Server]: https://www.microsoft.com/en-us/sql-server\n//! [PostgreSQL]: https://www.postgresql.org/\n//! [SQLite]: https://www.sqlite.org/\n//!\n//! [`mysql`]: crate::mysql\n//! [`postgres`]: crate::postgres\n//! [`mssql`]: crate::mssql\n//! [`sqlite`]: crate::sqlite\n//!\n//! ## Tier 2\n//!\n//! Tier 2 support can be thought as \"should work\". No specific automated testing is done,\n//! at this time, but there are efforts to ensure compatibility. Tier 2 support also includes\n//! database distributions that provide protocols that closely match a database from Tier 1.\n//!\n//! _No databases are in tier 2 at this time._\n//!\n//! # `Any`\n//!\n//! Selecting a database driver is, by default, a compile-time decision. SQLx is designed this way\n//! to take full advantage of the performance and type safety made available by Rust.\n//!\n//! We recognize that you may wish to make a runtime decision to decide the database driver. The\n//! [`Any`](crate::any) driver is provided for that purpose.\n//!\n//! ## Example\n//!\n//! ```rust,ignore\n//! // connect to SQLite\n//! let conn = AnyConnection::connect(\"sqlite://file.db\").await?;\n//!\n//! // connect to Postgres, no code change\n//! // required, decided by the scheme of the URL\n//! let conn = AnyConnection::connect(\"postgres://localhost/sqlx\").await?;\n//! ```\n\nuse std::fmt::Debug;\n\nuse crate::arguments::Arguments;\nuse crate::column::Column;\nuse crate::connection::Connection;\nuse crate::row::Row;\n\nuse crate::statement::Statement;\nuse crate::transaction::TransactionManager;\nuse crate::type_info::TypeInfo;\nuse crate::value::{Value, ValueRef};\n\n/// A database driver.\n///\n/// This trait encapsulates a complete set of traits that implement a driver for a\n/// specific database (e.g., MySQL, PostgreSQL).\npub trait Database: 'static + Sized + Send + Debug {\n    /// The concrete `Connection` implementation for this database.\n    type Connection: Connection<Database = Self>;\n\n    /// The concrete `TransactionManager` implementation for this database.\n    type TransactionManager: TransactionManager<Database = Self>;\n\n    /// The concrete `Row` implementation for this database.\n    type Row: Row<Database = Self>;\n\n    /// The concrete `QueryResult` implementation for this database.\n    type QueryResult: 'static + Sized + Send + Sync + Default + Extend<Self::QueryResult>;\n\n    /// The concrete `Column` implementation for this database.\n    type Column: Column<Database = Self>;\n\n    /// The concrete `TypeInfo` implementation for this database.\n    type TypeInfo: TypeInfo;\n\n    /// The concrete type used to hold an owned copy of the not-yet-decoded value that was\n    /// received from the database.\n    type Value: Value<Database = Self> + 'static;\n    /// The concrete type used to hold a reference to the not-yet-decoded value that has just been\n    /// received from the database.\n    type ValueRef<'r>: ValueRef<'r, Database = Self>;\n\n    /// The concrete `Arguments` implementation for this database.\n    type Arguments: Arguments<Database = Self>;\n    /// The concrete type used as a buffer for arguments while encoding.\n    type ArgumentBuffer;\n\n    /// The concrete `Statement` implementation for this database.\n    type Statement: Statement<Database = Self>;\n\n    /// The display name for this database driver.\n    const NAME: &'static str;\n\n    /// The schemes for database URLs that should match this driver.\n    const URL_SCHEMES: &'static [&'static str];\n}\n\n/// A [`Database`] that maintains a client-side cache of prepared statements.\npub trait HasStatementCache {}\n"
  },
  {
    "path": "sqlx-core/src/decode.rs",
    "content": "//! Provides [`Decode`] for decoding values from the database.\n\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::database::Database;\nuse crate::error::BoxDynError;\n\nuse crate::value::ValueRef;\n\n/// A type that can be decoded from the database.\n///\n/// ## How can I implement `Decode`?\n///\n/// A manual implementation of `Decode` can be useful when adding support for\n/// types externally to SQLx.\n///\n/// The following showcases how to implement `Decode` to be generic over [`Database`]. The\n/// implementation can be marginally simpler if you remove the `DB` type parameter and explicitly\n/// use the concrete [`ValueRef`](Database::ValueRef) and [`TypeInfo`](Database::TypeInfo) types.\n///\n/// ```rust\n/// # use sqlx_core::database::{Database};\n/// # use sqlx_core::decode::Decode;\n/// # use sqlx_core::types::Type;\n/// # use std::error::Error;\n/// #\n/// struct MyType;\n///\n/// # impl<DB: Database> Type<DB> for MyType {\n/// # fn type_info() -> DB::TypeInfo { todo!() }\n/// # }\n/// #\n/// # impl std::str::FromStr for MyType {\n/// # type Err = sqlx_core::error::Error;\n/// # fn from_str(s: &str) -> Result<Self, Self::Err> { todo!() }\n/// # }\n/// #\n/// // DB is the database driver\n/// // `'r` is the lifetime of the `Row` being decoded\n/// impl<'r, DB: Database> Decode<'r, DB> for MyType\n/// where\n///     // we want to delegate some of the work to string decoding so let's make sure strings\n///     // are supported by the database\n///     &'r str: Decode<'r, DB>\n/// {\n///     fn decode(\n///         value: <DB as Database>::ValueRef<'r>,\n///     ) -> Result<MyType, Box<dyn Error + 'static + Send + Sync>> {\n///         // the interface of ValueRef is largely unstable at the moment\n///         // so this is not directly implementable\n///\n///         // however, you can delegate to a type that matches the format of the type you want\n///         // to decode (such as a UTF-8 string)\n///\n///         let value = <&str as Decode<DB>>::decode(value)?;\n///\n///         // now you can parse this into your type (assuming there is a `FromStr`)\n///\n///         Ok(value.parse()?)\n///     }\n/// }\n/// ```\npub trait Decode<'r, DB: Database>: Sized {\n    /// Decode a new value of this type using a raw value from the database.\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError>;\n}\n\n// implement `Decode` for Option<T> for all SQL types\nimpl<'r, DB, T> Decode<'r, DB> for Option<T>\nwhere\n    DB: Database,\n    T: Decode<'r, DB>,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        if value.is_null() {\n            Ok(None)\n        } else {\n            Ok(Some(T::decode(value)?))\n        }\n    }\n}\n\nmacro_rules! impl_decode_for_smartpointer {\n    ($smart_pointer:tt) => {\n        impl<'r, DB, T> Decode<'r, DB> for $smart_pointer<T>\n        where\n            DB: Database,\n            T: Decode<'r, DB>,\n        {\n            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n                Ok(Self::new(T::decode(value)?))\n            }\n        }\n\n        impl<'r, DB> Decode<'r, DB> for $smart_pointer<str>\n        where\n            DB: Database,\n            &'r str: Decode<'r, DB>,\n        {\n            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n                let ref_str = <&str as Decode<DB>>::decode(value)?;\n                Ok(ref_str.into())\n            }\n        }\n\n        impl<'r, DB> Decode<'r, DB> for $smart_pointer<[u8]>\n        where\n            DB: Database,\n            Vec<u8>: Decode<'r, DB>,\n        {\n            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n                // The `Postgres` implementation requires this to be decoded as an owned value because\n                // bytes can be sent in text format.\n                let bytes = <Vec<u8> as Decode<DB>>::decode(value)?;\n                Ok(bytes.into())\n            }\n        }\n    };\n}\n\nimpl_decode_for_smartpointer!(Arc);\nimpl_decode_for_smartpointer!(Box);\nimpl_decode_for_smartpointer!(Rc);\n\n// implement `Decode` for Cow<T> for all SQL types\nimpl<'r, DB, T> Decode<'r, DB> for Cow<'_, T>\nwhere\n    DB: Database,\n    // `ToOwned` is required here to satisfy `Cow`\n    T: ToOwned + ?Sized,\n    <T as ToOwned>::Owned: Decode<'r, DB>,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        // See https://github.com/launchbadge/sqlx/pull/3674#discussion_r2008611502 for more info\n        // about why decoding to a `Cow::Owned` was chosen.\n        <<T as ToOwned>::Owned as Decode<DB>>::decode(value).map(Cow::Owned)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/describe.rs",
    "content": "use crate::database::Database;\nuse either::Either;\nuse std::convert::identity;\n\n/// Provides extended information on a statement.\n///\n/// Returned from [`Executor::describe`].\n///\n/// The query macros (e.g., `query!`, `query_as!`, etc.) use the information here to validate\n/// output and parameter types; and, generate an anonymous record.\n#[derive(Debug)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\n#[cfg_attr(\n    feature = \"offline\",\n    serde(bound(\n        serialize = \"DB::TypeInfo: serde::Serialize, DB::Column: serde::Serialize\",\n        deserialize = \"DB::TypeInfo: serde::de::DeserializeOwned, DB::Column: serde::de::DeserializeOwned\",\n    ))\n)]\n#[doc(hidden)]\npub struct Describe<DB: Database> {\n    pub columns: Vec<DB::Column>,\n    pub parameters: Option<Either<Vec<DB::TypeInfo>, usize>>,\n    pub nullable: Vec<Option<bool>>,\n}\n\nimpl<DB: Database> Describe<DB> {\n    /// Gets all columns in this statement.\n    pub fn columns(&self) -> &[DB::Column] {\n        &self.columns\n    }\n\n    /// Gets the column information at `index`.\n    ///\n    /// Panics if `index` is out of bounds.\n    pub fn column(&self, index: usize) -> &DB::Column {\n        &self.columns[index]\n    }\n\n    /// Gets the available information for parameters in this statement.\n    ///\n    /// Some drivers may return more or less than others. As an example, **PostgreSQL** will\n    /// return `Some(Either::Left(_))` with a full list of type information for each parameter.\n    /// However, **MSSQL** will return `None` as there is no information available.\n    pub fn parameters(&self) -> Option<Either<&[DB::TypeInfo], usize>> {\n        self.parameters.as_ref().map(|p| match p {\n            Either::Left(params) => Either::Left(&**params),\n            Either::Right(count) => Either::Right(*count),\n        })\n    }\n\n    /// Gets whether a column may be `NULL`, if this information is available.\n    pub fn nullable(&self, column: usize) -> Option<bool> {\n        self.nullable.get(column).copied().and_then(identity)\n    }\n}\n\n#[cfg(feature = \"any\")]\nimpl<DB: Database> Describe<DB> {\n    #[doc(hidden)]\n    pub fn try_into_any(self) -> crate::Result<Describe<crate::any::Any>>\n    where\n        crate::any::AnyColumn: for<'a> TryFrom<&'a DB::Column, Error = crate::Error>,\n        crate::any::AnyTypeInfo: for<'a> TryFrom<&'a DB::TypeInfo, Error = crate::Error>,\n    {\n        use crate::any::AnyTypeInfo;\n\n        let columns = self\n            .columns\n            .iter()\n            .map(crate::any::AnyColumn::try_from)\n            .collect::<Result<Vec<_>, _>>()?;\n\n        let parameters = match self.parameters {\n            Some(Either::Left(parameters)) => Some(Either::Left(\n                parameters\n                    .iter()\n                    .enumerate()\n                    .map(|(i, type_info)| {\n                        AnyTypeInfo::try_from(type_info).map_err(|_| {\n                            crate::Error::AnyDriverError(\n                                format!(\n                                    \"Any driver does not support type {type_info} of parameter {i}\"\n                                )\n                                .into(),\n                            )\n                        })\n                    })\n                    .collect::<Result<Vec<_>, _>>()?,\n            )),\n            Some(Either::Right(count)) => Some(Either::Right(count)),\n            None => None,\n        };\n\n        Ok(Describe {\n            columns,\n            parameters,\n            nullable: self.nullable,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/encode.rs",
    "content": "//! Provides [`Encode`] for encoding values for the database.\n\nuse std::borrow::Cow;\nuse std::mem;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::database::Database;\nuse crate::error::BoxDynError;\n\n/// The return type of [Encode::encode].\n#[must_use]\npub enum IsNull {\n    /// The value is null; no data was written.\n    Yes,\n\n    /// The value is not null.\n    ///\n    /// This does not mean that data was written.\n    No,\n}\n\nimpl IsNull {\n    pub fn is_null(&self) -> bool {\n        matches!(self, IsNull::Yes)\n    }\n}\n\n/// Encode a single value to be sent to the database.\npub trait Encode<'q, DB: Database> {\n    /// Writes the value of `self` into `buf` in the expected format for the database.\n    fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError>\n    where\n        Self: Sized,\n    {\n        self.encode_by_ref(buf)\n    }\n\n    /// Writes the value of `self` into `buf` without moving `self`.\n    ///\n    /// Where possible, make use of `encode` instead as it can take advantage of re-using\n    /// memory.\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError>;\n\n    fn produces(&self) -> Option<DB::TypeInfo> {\n        // `produces` is inherently a hook to allow database drivers to produce value-dependent\n        // type information; if the driver doesn't need this, it can leave this as `None`\n        None\n    }\n\n    #[inline]\n    fn size_hint(&self) -> usize {\n        mem::size_of_val(self)\n    }\n}\n\nimpl<'q, T, DB: Database> Encode<'q, DB> for &'_ T\nwhere\n    T: Encode<'q, DB>,\n{\n    #[inline]\n    fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        <T as Encode<DB>>::encode_by_ref(self, buf)\n    }\n\n    #[inline]\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <&T as Encode<DB>>::encode(self, buf)\n    }\n\n    #[inline]\n    fn produces(&self) -> Option<DB::TypeInfo> {\n        (**self).produces()\n    }\n\n    #[inline]\n    fn size_hint(&self) -> usize {\n        (**self).size_hint()\n    }\n}\n\n#[macro_export]\nmacro_rules! impl_encode_for_option {\n    ($DB:ident) => {\n        impl<'q, T> $crate::encode::Encode<'q, $DB> for Option<T>\n        where\n            T: $crate::encode::Encode<'q, $DB> + $crate::types::Type<$DB> + 'q,\n        {\n            #[inline]\n            fn produces(&self) -> Option<<$DB as $crate::database::Database>::TypeInfo> {\n                if let Some(v) = self {\n                    v.produces()\n                } else {\n                    T::type_info().into()\n                }\n            }\n\n            #[inline]\n            fn encode(\n                self,\n                buf: &mut <$DB as $crate::database::Database>::ArgumentBuffer,\n            ) -> Result<$crate::encode::IsNull, $crate::error::BoxDynError> {\n                if let Some(v) = self {\n                    v.encode(buf)\n                } else {\n                    Ok($crate::encode::IsNull::Yes)\n                }\n            }\n\n            #[inline]\n            fn encode_by_ref(\n                &self,\n                buf: &mut <$DB as $crate::database::Database>::ArgumentBuffer,\n            ) -> Result<$crate::encode::IsNull, $crate::error::BoxDynError> {\n                if let Some(v) = self {\n                    v.encode_by_ref(buf)\n                } else {\n                    Ok($crate::encode::IsNull::Yes)\n                }\n            }\n\n            #[inline]\n            fn size_hint(&self) -> usize {\n                self.as_ref().map_or(0, $crate::encode::Encode::size_hint)\n            }\n        }\n    };\n}\n\nmacro_rules! impl_encode_for_smartpointer {\n    ($smart_pointer:ty) => {\n        impl<'q, T, DB: Database> Encode<'q, DB> for $smart_pointer\n        where\n            T: Encode<'q, DB>,\n        {\n            #[inline]\n            fn encode(\n                self,\n                buf: &mut <DB as Database>::ArgumentBuffer,\n            ) -> Result<IsNull, BoxDynError> {\n                <T as Encode<DB>>::encode_by_ref(self.as_ref(), buf)\n            }\n\n            #[inline]\n            fn encode_by_ref(\n                &self,\n                buf: &mut <DB as Database>::ArgumentBuffer,\n            ) -> Result<IsNull, BoxDynError> {\n                <&T as Encode<DB>>::encode(self, buf)\n            }\n\n            #[inline]\n            fn produces(&self) -> Option<DB::TypeInfo> {\n                (**self).produces()\n            }\n\n            #[inline]\n            fn size_hint(&self) -> usize {\n                (**self).size_hint()\n            }\n        }\n    };\n}\n\nimpl_encode_for_smartpointer!(Arc<T>);\nimpl_encode_for_smartpointer!(Box<T>);\nimpl_encode_for_smartpointer!(Rc<T>);\n\nimpl<'q, T, DB: Database> Encode<'q, DB> for Cow<'q, T>\nwhere\n    T: Encode<'q, DB>,\n    T: ToOwned,\n{\n    #[inline]\n    fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        <&T as Encode<DB>>::encode_by_ref(&self.as_ref(), buf)\n    }\n\n    #[inline]\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <&T as Encode<DB>>::encode_by_ref(&self.as_ref(), buf)\n    }\n\n    #[inline]\n    fn produces(&self) -> Option<DB::TypeInfo> {\n        <&T as Encode<DB>>::produces(&self.as_ref())\n    }\n\n    #[inline]\n    fn size_hint(&self) -> usize {\n        <&T as Encode<DB>>::size_hint(&self.as_ref())\n    }\n}\n\n#[macro_export]\nmacro_rules! forward_encode_impl {\n    ($for_type:ty, $forward_to:ty, $db:ident) => {\n        impl<'q> Encode<'q, $db> for $for_type {\n            fn encode_by_ref(\n                &self,\n                buf: &mut <$db as sqlx_core::database::Database>::ArgumentBuffer,\n            ) -> Result<IsNull, BoxDynError> {\n                <$forward_to as Encode<$db>>::encode(self.as_ref(), buf)\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "sqlx-core/src/error.rs",
    "content": "//! Types for working with errors produced by SQLx.\n\nuse std::any::type_name;\nuse std::borrow::Cow;\nuse std::error::Error as StdError;\nuse std::fmt::Display;\nuse std::io;\n\nuse crate::database::Database;\n\nuse crate::type_info::TypeInfo;\nuse crate::types::Type;\n\n/// A specialized `Result` type for SQLx.\npub type Result<T, E = Error> = ::std::result::Result<T, E>;\n\n// Convenience type alias for usage within SQLx.\n// Do not make this type public.\npub type BoxDynError = Box<dyn StdError + 'static + Send + Sync>;\n\n/// An unexpected `NULL` was encountered during decoding.\n///\n/// Returned from [`Row::get`](crate::row::Row::get) if the value from the database is `NULL`,\n/// and you are not decoding into an `Option`.\n#[derive(thiserror::Error, Debug)]\n#[error(\"unexpected null; try decoding as an `Option`\")]\npub struct UnexpectedNullError;\n\n/// Represents all the ways a method can fail within SQLx.\n#[derive(Debug, thiserror::Error)]\n#[non_exhaustive]\npub enum Error {\n    /// Error occurred while parsing a connection string.\n    #[error(\"error with configuration: {0}\")]\n    Configuration(#[source] BoxDynError),\n\n    /// One or more of the arguments to the called function was invalid.\n    ///\n    /// The string contains more information.\n    #[error(\"{0}\")]\n    InvalidArgument(String),\n\n    /// Error returned from the database.\n    #[error(\"error returned from database: {0}\")]\n    Database(#[source] Box<dyn DatabaseError>),\n\n    /// Error communicating with the database backend.\n    #[error(\"error communicating with database: {0}\")]\n    Io(#[from] io::Error),\n\n    /// Error occurred while attempting to establish a TLS connection.\n    #[error(\"error occurred while attempting to establish a TLS connection: {0}\")]\n    Tls(#[source] BoxDynError),\n\n    /// Unexpected or invalid data encountered while communicating with the database.\n    ///\n    /// This should indicate there is a programming error in a SQLx driver or there\n    /// is something corrupted with the connection to the database itself.\n    #[error(\"encountered unexpected or invalid data: {0}\")]\n    Protocol(String),\n\n    /// No rows returned by a query that expected to return at least one row.\n    #[error(\"no rows returned by a query that expected to return at least one row\")]\n    RowNotFound,\n\n    /// Type in query doesn't exist. Likely due to typo or missing user type.\n    #[error(\"type named {type_name} not found\")]\n    TypeNotFound { type_name: String },\n\n    /// Column index was out of bounds.\n    #[error(\"column index out of bounds: the len is {len}, but the index is {index}\")]\n    ColumnIndexOutOfBounds { index: usize, len: usize },\n\n    /// No column found for the given name.\n    #[error(\"no column found for name: {0}\")]\n    ColumnNotFound(String),\n\n    /// Error occurred while decoding a value from a specific column.\n    #[error(\"error occurred while decoding column {index}: {source}\")]\n    ColumnDecode {\n        index: String,\n\n        #[source]\n        source: BoxDynError,\n    },\n\n    /// Error occurred while encoding a value.\n    #[error(\"error occurred while encoding a value: {0}\")]\n    Encode(#[source] BoxDynError),\n\n    /// Error occurred while decoding a value.\n    #[error(\"error occurred while decoding: {0}\")]\n    Decode(#[source] BoxDynError),\n\n    /// Error occurred within the `Any` driver mapping to/from the native driver.\n    #[error(\"error in Any driver mapping: {0}\")]\n    AnyDriverError(#[source] BoxDynError),\n\n    /// A [`Pool::acquire`] timed out due to connections not becoming available or\n    /// because another task encountered too many errors while trying to open a new connection.\n    ///\n    /// [`Pool::acquire`]: crate::pool::Pool::acquire\n    #[error(\"pool timed out while waiting for an open connection\")]\n    PoolTimedOut,\n\n    /// [`Pool::close`] was called while we were waiting in [`Pool::acquire`].\n    ///\n    /// [`Pool::acquire`]: crate::pool::Pool::acquire\n    /// [`Pool::close`]: crate::pool::Pool::close\n    #[error(\"attempted to acquire a connection on a closed pool\")]\n    PoolClosed,\n\n    /// A background worker has crashed.\n    #[error(\"attempted to communicate with a crashed background worker\")]\n    WorkerCrashed,\n\n    #[cfg(feature = \"migrate\")]\n    #[error(\"{0}\")]\n    Migrate(#[source] Box<crate::migrate::MigrateError>),\n\n    #[error(\"attempted to call begin_with at non-zero transaction depth\")]\n    InvalidSavePointStatement,\n\n    #[error(\"got unexpected connection status after attempting to begin transaction\")]\n    BeginFailed,\n\n    // Not returned in normal operation.\n    /// Error occurred while reading configuration file\n    #[doc(hidden)]\n    #[error(\"error reading configuration file: {0}\")]\n    ConfigFile(#[from] crate::config::ConfigError),\n}\n\nimpl StdError for Box<dyn DatabaseError> {}\n\nimpl Error {\n    pub fn into_database_error(self) -> Option<Box<dyn DatabaseError + 'static>> {\n        match self {\n            Error::Database(err) => Some(err),\n            _ => None,\n        }\n    }\n\n    pub fn as_database_error(&self) -> Option<&(dyn DatabaseError + 'static)> {\n        match self {\n            Error::Database(err) => Some(&**err),\n            _ => None,\n        }\n    }\n\n    #[doc(hidden)]\n    #[inline]\n    pub fn protocol(err: impl Display) -> Self {\n        Error::Protocol(err.to_string())\n    }\n\n    #[doc(hidden)]\n    #[inline]\n    pub fn database(err: impl DatabaseError) -> Self {\n        Error::Database(Box::new(err))\n    }\n\n    #[doc(hidden)]\n    #[inline]\n    pub fn config(err: impl StdError + Send + Sync + 'static) -> Self {\n        Error::Configuration(err.into())\n    }\n\n    pub(crate) fn tls(err: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {\n        Error::Tls(err.into())\n    }\n\n    #[doc(hidden)]\n    #[inline]\n    pub fn decode(err: impl Into<Box<dyn StdError + Send + Sync + 'static>>) -> Self {\n        Error::Decode(err.into())\n    }\n}\n\npub fn mismatched_types<DB: Database, T: Type<DB>>(ty: &DB::TypeInfo) -> BoxDynError {\n    // TODO: `#name` only produces `TINYINT` but perhaps we want to show `TINYINT(1)`\n    format!(\n        \"mismatched types; Rust type `{}` (as SQL type `{}`) is not compatible with SQL type `{}`\",\n        type_name::<T>(),\n        T::type_info().name(),\n        ty.name()\n    )\n    .into()\n}\n\n/// The error kind.\n///\n/// This enum is to be used to identify frequent errors that can be handled by the program.\n/// Although it currently only supports constraint violations, the type may grow in the future.\n#[derive(Debug, PartialEq, Eq)]\n#[non_exhaustive]\npub enum ErrorKind {\n    /// Unique/primary key constraint violation.\n    UniqueViolation,\n    /// Foreign key constraint violation.\n    ForeignKeyViolation,\n    /// Not-null constraint violation.\n    NotNullViolation,\n    /// Check constraint violation.\n    CheckViolation,\n    /// Exclusion constraint violation.\n    ExclusionViolation,\n    /// An unmapped error.\n    Other,\n}\n\n/// An error that was returned from the database.\npub trait DatabaseError: 'static + Send + Sync + StdError {\n    /// The primary, human-readable error message.\n    fn message(&self) -> &str;\n\n    /// The (SQLSTATE) code for the error.\n    fn code(&self) -> Option<Cow<'_, str>> {\n        None\n    }\n\n    #[doc(hidden)]\n    fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static);\n\n    #[doc(hidden)]\n    fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static);\n\n    #[doc(hidden)]\n    fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static>;\n\n    #[doc(hidden)]\n    fn is_transient_in_connect_phase(&self) -> bool {\n        false\n    }\n\n    /// Returns the name of the constraint that triggered the error, if applicable.\n    /// If the error was caused by a conflict of a unique index, this will be the index name.\n    ///\n    /// ### Note\n    /// Currently only populated by the Postgres driver.\n    fn constraint(&self) -> Option<&str> {\n        None\n    }\n\n    /// Returns the name of the table that was affected by the error, if applicable.\n    ///\n    /// ### Note\n    /// Currently only populated by the Postgres driver.\n    fn table(&self) -> Option<&str> {\n        None\n    }\n\n    /// Returns the kind of the error, if supported.\n    ///\n    /// ### Note\n    /// Not all back-ends behave the same when reporting the error code.\n    fn kind(&self) -> ErrorKind;\n\n    /// Returns whether the error kind is a violation of a unique/primary key constraint.\n    fn is_unique_violation(&self) -> bool {\n        matches!(self.kind(), ErrorKind::UniqueViolation)\n    }\n\n    /// Returns whether the error kind is a violation of a foreign key.\n    fn is_foreign_key_violation(&self) -> bool {\n        matches!(self.kind(), ErrorKind::ForeignKeyViolation)\n    }\n\n    /// Returns whether the error kind is a violation of a check.\n    fn is_check_violation(&self) -> bool {\n        matches!(self.kind(), ErrorKind::CheckViolation)\n    }\n}\n\nimpl dyn DatabaseError {\n    /// Downcast a reference to this generic database error to a specific\n    /// database error type.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the database error type is not `E`. This is a deliberate contrast from\n    /// `Error::downcast_ref` which returns `Option<&E>`. In normal usage, you should know the\n    /// specific error type. In other cases, use `try_downcast_ref`.\n    pub fn downcast_ref<E: DatabaseError>(&self) -> &E {\n        self.try_downcast_ref().unwrap_or_else(|| {\n            panic!(\"downcast to wrong DatabaseError type; original error: {self}\")\n        })\n    }\n\n    /// Downcast this generic database error to a specific database error type.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the database error type is not `E`. This is a deliberate contrast from\n    /// `Error::downcast` which returns `Option<E>`. In normal usage, you should know the\n    /// specific error type. In other cases, use `try_downcast`.\n    pub fn downcast<E: DatabaseError>(self: Box<Self>) -> Box<E> {\n        self.try_downcast()\n            .unwrap_or_else(|e| panic!(\"downcast to wrong DatabaseError type; original error: {e}\"))\n    }\n\n    /// Downcast a reference to this generic database error to a specific\n    /// database error type.\n    #[inline]\n    pub fn try_downcast_ref<E: DatabaseError>(&self) -> Option<&E> {\n        self.as_error().downcast_ref()\n    }\n\n    /// Downcast this generic database error to a specific database error type.\n    #[inline]\n    pub fn try_downcast<E: DatabaseError>(self: Box<Self>) -> Result<Box<E>, Box<Self>> {\n        if self.as_error().is::<E>() {\n            Ok(self.into_error().downcast().unwrap())\n        } else {\n            Err(self)\n        }\n    }\n}\n\nimpl<E> From<E> for Error\nwhere\n    E: DatabaseError,\n{\n    #[inline]\n    fn from(error: E) -> Self {\n        Error::Database(Box::new(error))\n    }\n}\n\n#[cfg(feature = \"migrate\")]\nimpl From<crate::migrate::MigrateError> for Error {\n    #[inline]\n    fn from(error: crate::migrate::MigrateError) -> Self {\n        Error::Migrate(Box::new(error))\n    }\n}\n\n/// Format an error message as a `Protocol` error\n#[macro_export]\nmacro_rules! err_protocol {\n    ($($fmt_args:tt)*) => {\n        $crate::error::Error::Protocol(\n            format!(\n                \"{} ({}:{})\",\n                // Note: the format string needs to be unmodified (e.g. by `concat!()`)\n                // for implicit formatting arguments to work\n                format_args!($($fmt_args)*),\n                module_path!(),\n                line!(),\n            )\n        )\n    };\n}\n"
  },
  {
    "path": "sqlx-core/src/executor.rs",
    "content": "use crate::database::Database;\nuse crate::error::{BoxDynError, Error};\nuse crate::sql_str::{SqlSafeStr, SqlStr};\n\nuse either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};\nuse std::{fmt::Debug, future};\n\n/// A type that contains or can provide a database\n/// connection to use for executing queries against the database.\n///\n/// No guarantees are provided that successive queries run on the same\n/// physical database connection.\n///\n/// A [`Connection`](crate::connection::Connection) is an `Executor` that guarantees that\n/// successive queries are ran on the same physical database connection.\n///\n/// Implemented for the following:\n///\n///  * [`&Pool`](super::pool::Pool)\n///  * [`&mut Connection`](super::connection::Connection)\n///\n/// The [`Executor`] impls for [`Transaction`](crate::transaction::Transaction)\n/// and [`PoolConnection`](crate::pool::PoolConnection) have been deleted because they\n/// cannot exist in the new crate architecture without rewriting the Executor trait entirely.\n/// To fix this breakage, simply add a dereference where an impl [`Executor`] is expected, as\n/// they both dereference to the inner connection type which will still implement it:\n/// * `&mut transaction` -> `&mut *transaction`\n/// * `&mut connection` -> `&mut *connection`\n///\npub trait Executor<'c>: Send + Debug + Sized {\n    type Database: Database;\n\n    /// Execute the query and return the total number of rows affected.\n    fn execute<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxFuture<'e, Result<<Self::Database as Database>::QueryResult, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        self.execute_many(query).try_collect().boxed()\n    }\n\n    /// Execute multiple queries and return the rows affected from each query, in a stream.\n    fn execute_many<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxStream<'e, Result<<Self::Database as Database>::QueryResult, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        self.fetch_many(query)\n            .try_filter_map(|step| async move {\n                Ok(match step {\n                    Either::Left(rows) => Some(rows),\n                    Either::Right(_) => None,\n                })\n            })\n            .boxed()\n    }\n\n    /// Execute the query and return the generated results as a stream.\n    fn fetch<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxStream<'e, Result<<Self::Database as Database>::Row, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        self.fetch_many(query)\n            .try_filter_map(|step| async move {\n                Ok(match step {\n                    Either::Left(_) => None,\n                    Either::Right(row) => Some(row),\n                })\n            })\n            .boxed()\n    }\n\n    /// Execute multiple queries and return the generated results as a stream\n    /// from each query, in a stream.\n    fn fetch_many<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxStream<\n        'e,\n        Result<\n            Either<<Self::Database as Database>::QueryResult, <Self::Database as Database>::Row>,\n            Error,\n        >,\n    >\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>;\n\n    /// Execute the query and return all the generated results, collected into a [`Vec`].\n    fn fetch_all<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxFuture<'e, Result<Vec<<Self::Database as Database>::Row>, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        self.fetch(query).try_collect().boxed()\n    }\n\n    /// Execute the query and returns exactly one row.\n    fn fetch_one<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxFuture<'e, Result<<Self::Database as Database>::Row, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        self.fetch_optional(query)\n            .and_then(|row| {\n                future::ready(match row {\n                    Some(row) => Ok(row),\n                    None => Err(Error::RowNotFound),\n                })\n            })\n            .boxed()\n    }\n\n    /// Execute the query and returns at most one row.\n    fn fetch_optional<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxFuture<'e, Result<Option<<Self::Database as Database>::Row>, Error>>\n    where\n        'c: 'e,\n        E: 'q + Execute<'q, Self::Database>;\n\n    /// Prepare the SQL query to inspect the type information of its parameters\n    /// and results.\n    ///\n    /// Be advised that when using the `query`, `query_as`, or `query_scalar` functions, the query\n    /// is transparently prepared and executed.\n    ///\n    /// This explicit API is provided to allow access to the statement metadata available after\n    /// it prepared but before the first row is returned.\n    #[inline]\n    fn prepare<'e>(\n        self,\n        query: SqlStr,\n    ) -> BoxFuture<'e, Result<<Self::Database as Database>::Statement, Error>>\n    where\n        'c: 'e,\n    {\n        self.prepare_with(query, &[])\n    }\n\n    /// Prepare the SQL query, with parameter type information, to inspect the\n    /// type information about its parameters and results.\n    ///\n    /// Only some database drivers (PostgreSQL, MSSQL) can take advantage of\n    /// this extra information to influence parameter type inference.\n    fn prepare_with<'e>(\n        self,\n        sql: SqlStr,\n        parameters: &'e [<Self::Database as Database>::TypeInfo],\n    ) -> BoxFuture<'e, Result<<Self::Database as Database>::Statement, Error>>\n    where\n        'c: 'e;\n\n    /// Describe the SQL query and return type information about its parameters\n    /// and results.\n    ///\n    /// This is used by compile-time verification in the query macros to\n    /// power their type inference.\n    #[doc(hidden)]\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        sql: SqlStr,\n    ) -> BoxFuture<'e, Result<crate::describe::Describe<Self::Database>, Error>>\n    where\n        'c: 'e;\n}\n\n/// A type that may be executed against a database connection.\n///\n/// Implemented for the following:\n///\n///  * [`&str`](std::str)\n///  * [`Query`](super::query::Query)\n///\npub trait Execute<'q, DB: Database>: Send + Sized {\n    /// Gets the SQL that will be executed.\n    fn sql(self) -> SqlStr;\n\n    /// Gets the previously cached statement, if available.\n    fn statement(&self) -> Option<&DB::Statement>;\n\n    /// Returns the arguments to be bound against the query string.\n    ///\n    /// Returning `Ok(None)` for `Arguments` indicates to use a \"simple\" query protocol and to not\n    /// prepare the query. Returning `Ok(Some(Default::default()))` is an empty arguments object that\n    /// will be prepared (and cached) before execution.\n    ///\n    /// Returns `Err` if encoding any of the arguments failed.\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError>;\n\n    /// Returns `true` if the statement should be cached.\n    fn persistent(&self) -> bool;\n}\n\nimpl<DB: Database, T> Execute<'_, DB> for T\nwhere\n    T: SqlSafeStr + Send,\n{\n    #[inline]\n    fn sql(self) -> SqlStr {\n        self.into_sql_str()\n    }\n\n    #[inline]\n    fn statement(&self) -> Option<&DB::Statement> {\n        None\n    }\n\n    #[inline]\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        Ok(None)\n    }\n\n    #[inline]\n    fn persistent(&self) -> bool {\n        true\n    }\n}\n\nimpl<DB: Database, T> Execute<'_, DB> for (T, Option<<DB as Database>::Arguments>)\nwhere\n    T: SqlSafeStr + Send,\n{\n    #[inline]\n    fn sql(self) -> SqlStr {\n        self.0.into_sql_str()\n    }\n\n    #[inline]\n    fn statement(&self) -> Option<&DB::Statement> {\n        None\n    }\n\n    #[inline]\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        Ok(self.1.take())\n    }\n\n    #[inline]\n    fn persistent(&self) -> bool {\n        true\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/ext/async_stream.rs",
    "content": "//! A minimalist clone of the `async-stream` crate in 100% safe code, without proc macros.\n//!\n//! This was created initially to get around some weird compiler errors we were getting with\n//! `async-stream`, and now it'd just be more work to replace.\n\nuse std::future::{self, Future};\nuse std::pin::Pin;\nuse std::sync::{Arc, Mutex};\nuse std::task::{Context, Poll};\n\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::Stream;\nuse futures_core::FusedFuture;\nuse futures_util::future::Fuse;\nuse futures_util::FutureExt;\n\nuse crate::error::Error;\n\npub struct TryAsyncStream<'a, T> {\n    yielder: Yielder<T>,\n    future: Fuse<BoxFuture<'a, Result<(), Error>>>,\n}\n\nimpl<'a, T> TryAsyncStream<'a, T> {\n    pub fn new<F, Fut>(f: F) -> Self\n    where\n        F: FnOnce(Yielder<T>) -> Fut + Send,\n        Fut: 'a + Future<Output = Result<(), Error>> + Send,\n        T: 'a + Send,\n    {\n        let yielder = Yielder::new();\n\n        let future = f(yielder.duplicate()).boxed().fuse();\n\n        Self { future, yielder }\n    }\n}\n\npub struct Yielder<T> {\n    // This mutex should never have any contention in normal operation.\n    // We're just using it because `Rc<Cell<Option<T>>>` would not be `Send`.\n    value: Arc<Mutex<Option<T>>>,\n}\n\nimpl<T> Yielder<T> {\n    fn new() -> Self {\n        Yielder {\n            value: Arc::new(Mutex::new(None)),\n        }\n    }\n\n    // Don't want to expose a `Clone` impl\n    fn duplicate(&self) -> Self {\n        Yielder {\n            value: self.value.clone(),\n        }\n    }\n\n    /// NOTE: may deadlock the task if called from outside the future passed to `TryAsyncStream`.\n    pub async fn r#yield(&self, val: T) {\n        let replaced = self\n            .value\n            .lock()\n            .expect(\"BUG: panicked while holding a lock\")\n            .replace(val);\n\n        debug_assert!(\n            replaced.is_none(),\n            \"BUG: previously yielded value not taken\"\n        );\n\n        let mut yielded = false;\n\n        // Allows the generating future to suspend its execution without changing the task priority,\n        // which would happen with `tokio::task::yield_now()`.\n        //\n        // Note that because this has no way to schedule a wakeup, this could deadlock the task\n        // if called in the wrong place.\n        future::poll_fn(|_cx| {\n            if !yielded {\n                yielded = true;\n                Poll::Pending\n            } else {\n                Poll::Ready(())\n            }\n        })\n        .await\n    }\n\n    fn take(&self) -> Option<T> {\n        self.value\n            .lock()\n            .expect(\"BUG: panicked while holding a lock\")\n            .take()\n    }\n}\n\nimpl<T> Stream for TryAsyncStream<'_, T> {\n    type Item = Result<T, Error>;\n\n    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {\n        if self.future.is_terminated() {\n            return Poll::Ready(None);\n        }\n\n        match self.future.poll_unpin(cx) {\n            Poll::Ready(Ok(())) => {\n                // Future returned without yielding another value,\n                // or else it would have returned `Pending` instead.\n                Poll::Ready(None)\n            }\n            Poll::Ready(Err(e)) => Poll::Ready(Some(Err(e))),\n            Poll::Pending => self\n                .yielder\n                .take()\n                .map_or(Poll::Pending, |val| Poll::Ready(Some(Ok(val)))),\n        }\n    }\n}\n\n#[macro_export]\nmacro_rules! try_stream {\n    ($($block:tt)*) => {\n        $crate::ext::async_stream::TryAsyncStream::new(move |yielder| ::tracing::Instrument::in_current_span(async move {\n            // Anti-footgun: effectively pins `yielder` to this future to prevent any accidental\n            // move to another task, which could deadlock.\n            let yielder = &yielder;\n\n            macro_rules! r#yield {\n                ($v:expr) => {{\n                    yielder.r#yield($v).await;\n                }}\n            }\n\n            $($block)*\n        }))\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/ext/mod.rs",
    "content": "pub mod ustr;\n\n#[macro_use]\npub mod async_stream;\n"
  },
  {
    "path": "sqlx-core/src/ext/ustr.rs",
    "content": "use std::borrow::Borrow;\nuse std::fmt::{self, Debug, Display, Formatter};\nuse std::hash::{Hash, Hasher};\nuse std::ops::Deref;\nuse std::sync::Arc;\n\n// U meaning micro\n// a micro-string is either a reference-counted string or a static string\n// this guarantees these are cheap to clone everywhere\n#[derive(Clone, Eq)]\npub enum UStr {\n    Static(&'static str),\n    Shared(Arc<str>),\n}\n\nimpl UStr {\n    pub fn new(s: &str) -> Self {\n        UStr::Shared(Arc::from(s.to_owned()))\n    }\n\n    /// Apply [str::strip_prefix], without copying if possible.\n    pub fn strip_prefix(this: &Self, prefix: &str) -> Option<Self> {\n        match this {\n            UStr::Static(s) => s.strip_prefix(prefix).map(Self::Static),\n            UStr::Shared(s) => s.strip_prefix(prefix).map(|s| Self::Shared(s.into())),\n        }\n    }\n}\n\nimpl Deref for UStr {\n    type Target = str;\n\n    #[inline]\n    fn deref(&self) -> &str {\n        match self {\n            UStr::Static(s) => s,\n            UStr::Shared(s) => s,\n        }\n    }\n}\n\nimpl Hash for UStr {\n    #[inline]\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        // Forward the hash to the string representation of this\n        // A derive(Hash) encodes the enum discriminant\n        (**self).hash(state);\n    }\n}\n\nimpl Borrow<str> for UStr {\n    #[inline]\n    fn borrow(&self) -> &str {\n        self\n    }\n}\n\nimpl PartialEq<UStr> for UStr {\n    fn eq(&self, other: &UStr) -> bool {\n        (**self).eq(&**other)\n    }\n}\n\nimpl From<&'static str> for UStr {\n    #[inline]\n    fn from(s: &'static str) -> Self {\n        UStr::Static(s)\n    }\n}\n\nimpl<'a> From<&'a UStr> for UStr {\n    fn from(value: &'a UStr) -> Self {\n        value.clone()\n    }\n}\n\nimpl From<String> for UStr {\n    #[inline]\n    fn from(s: String) -> Self {\n        UStr::Shared(s.into())\n    }\n}\n\nimpl Debug for UStr {\n    #[inline]\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.pad(self)\n    }\n}\n\nimpl Display for UStr {\n    #[inline]\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.pad(self)\n    }\n}\n\n// manual impls because otherwise things get a little screwy with lifetimes\n\n#[cfg(feature = \"offline\")]\nimpl<'de> serde::Deserialize<'de> for UStr {\n    fn deserialize<D>(deserializer: D) -> Result<Self, <D as serde::Deserializer<'de>>::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        Ok(String::deserialize(deserializer)?.into())\n    }\n}\n\n#[cfg(feature = \"offline\")]\nimpl serde::Serialize for UStr {\n    fn serialize<S>(\n        &self,\n        serializer: S,\n    ) -> Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>\n    where\n        S: serde::Serializer,\n    {\n        serializer.serialize_str(self)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/from_row.rs",
    "content": "use crate::{error::Error, row::Row};\n\n/// A record that can be built from a row returned by the database.\n///\n/// In order to use [`query_as`](crate::query_as) the output type must implement `FromRow`.\n///\n/// ## Derivable\n///\n/// This trait can be derived by SQLx for any struct. The generated implementation\n/// will consist of a sequence of calls to [`Row::try_get`] using the name from each\n/// struct field.\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n/// }\n/// ```\n///\n/// ### Field attributes\n///\n/// Several attributes can be specified to customize how each column in a row is read:\n///\n/// #### `rename`\n///\n/// When the name of a field in Rust does not match the name of its corresponding column,\n/// you can use the `rename` attribute to specify the name that the field has in the row.\n/// For example:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n///     #[sqlx(rename = \"description\")]\n///     about_me: String\n/// }\n/// ```\n///\n/// Given a query such as:\n///\n/// ```sql\n/// SELECT id, name, description FROM users;\n/// ```\n///\n/// will read the content of the column `description` into the field `about_me`.\n///\n/// #### `rename_all`\n/// By default, field names are expected verbatim (with the exception of the raw identifier prefix `r#`, if present).\n/// Placed at the struct level, this attribute changes how the field name is mapped to its SQL column name:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// #[sqlx(rename_all = \"camelCase\")]\n/// struct UserPost {\n///     id: i32,\n///     // remapped to \"userId\"\n///     user_id: i32,\n///     contents: String\n/// }\n/// ```\n///\n/// The supported values are `snake_case` (available if you have non-snake-case field names for some\n/// reason), `lowercase`, `UPPERCASE`, `camelCase`, `PascalCase`, `SCREAMING_SNAKE_CASE` and `kebab-case`.\n/// The styling of each option is intended to be an example of its behavior.\n///\n/// Case conversion is handled by the `heck` crate.\n/// See [its documentation](https://docs.rs/heck/0.5.0/heck/#definition-of-a-word-boundary)\n/// for details.\n///\n/// Note that numbers are *not* considered separate words.\n/// For example, `Foo1` to snake case would be `foo1`, *not* `foo_1`.\n/// See [this issue](https://github.com/launchbadge/sqlx/issues/3864) for discussion.\n///\n/// #### `default`\n///\n/// When your struct contains a field that is not present in your query,\n/// if the field type has an implementation for [`Default`],\n/// you can use the `default` attribute to assign the default value to said field.\n/// For example:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n///     #[sqlx(default)]\n///     location: Option<String>\n/// }\n/// ```\n///\n/// Given a query such as:\n///\n/// ```sql\n/// SELECT id, name FROM users;\n/// ```\n///\n/// will set the value of the field `location` to the default value of `Option<String>`,\n/// which is `None`.\n///\n/// Moreover, if the struct has an implementation for [`Default`], you can use the `default`\n/// attribute at the struct level rather than for each single field. If a field does not appear in the result,\n/// its value is taken from the `Default` implementation for the struct.\n/// For example:\n///\n/// ```rust, ignore\n/// #[derive(Default, sqlx::FromRow)]\n/// #[sqlx(default)]\n/// struct Options {\n///     option_a: Option<i32>,\n///     option_b: Option<String>,\n///     option_c: Option<bool>,\n/// }\n/// ```\n///\n/// For a derived `Default` implementation this effectively populates each missing field\n/// with `Default::default()`, but a manual `Default` implementation can provide\n/// different placeholder values, if applicable.\n///\n/// This is similar to how `#[serde(default)]` behaves.\n///\n/// #### `flatten`\n///\n/// If you want to handle a field that implements [`FromRow`],\n/// you can use the `flatten` attribute to specify that you want\n/// it to use [`FromRow`] for parsing rather than the usual method.\n/// For example:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// struct Address {\n///     country: String,\n///     city: String,\n///     road: String,\n/// }\n///\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n///     #[sqlx(flatten)]\n///     address: Address,\n/// }\n/// ```\n/// Given a query such as:\n///\n/// ```sql\n/// SELECT id, name, country, city, road FROM users;\n/// ```\n///\n/// This field is compatible with the `default` attribute.\n///\n/// #### `skip`\n///\n/// This is a variant of the `default` attribute which instead always takes the value from\n/// the `Default` implementation for this field type ignoring any results in your query.\n/// This can be useful, if some field does not satifisfy the trait bounds (i.e.\n/// `sqlx::decode::Decode`, `sqlx::type::Type`), in particular in case of nested structures.\n/// For example:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// struct Address {\n///     user_name: String,\n///     street: String,\n///     city: String,\n/// }\n///\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     name: String,\n///     #[sqlx(skip)]\n///     addresses: Vec<Address>,\n/// }\n/// ```\n///\n/// Then when querying into `User`, only `name` needs to be set:\n///\n/// ```rust,ignore\n/// let user: User = sqlx::query_as(\"SELECT name FROM users\")\n///    .fetch_one(&mut some_connection)\n///    .await?;\n///\n/// // `Default` for `Vec<Address>` is an empty vector.\n/// assert!(user.addresses.is_empty());\n/// ```\n///\n/// #### `try_from`\n///\n/// When your struct contains a field whose type is not matched with the database type,\n/// if the field type has an implementation [`TryFrom`] for the database type,\n/// you can use the `try_from` attribute to convert the database type to the field type.\n/// For example:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n///     #[sqlx(try_from = \"i64\")]\n///     bigIntInMySql: u64\n/// }\n/// ```\n///\n/// Given a query such as:\n///\n/// ```sql\n/// SELECT id, name, bigIntInMySql FROM users;\n/// ```\n///\n/// In MySql, `BigInt` type matches `i64`, but you can convert it to `u64` by `try_from`.\n///\n/// #### `json`\n///\n/// If your database supports a JSON type, you can leverage `#[sqlx(json)]`\n/// to automatically integrate JSON deserialization in your [`FromRow`] implementation using [`serde`](https://docs.rs/serde/latest/serde/).\n///\n/// ```rust,ignore\n/// #[derive(serde::Deserialize)]\n/// struct Data {\n///     field1: String,\n///     field2: u64\n/// }\n///\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n///     #[sqlx(json)]\n///     metadata: Data\n/// }\n/// ```\n///\n/// Given a query like the following:\n///\n/// ```sql\n/// SELECT\n///     1 AS id,\n///     'Name' AS name,\n///     JSON_OBJECT('field1', 'value1', 'field2', 42) AS metadata\n/// ```\n///\n/// The `metadata` field will be deserialized used its `serde::Deserialize` implementation:\n///\n/// ```rust,ignore\n/// User {\n///     id: 1,\n///     name: \"Name\",\n///     metadata: Data {\n///         field1: \"value1\",\n///         field2: 42\n///     }\n/// }\n/// ```\n///\n/// By default the `#[sqlx(json)]` attribute will assume that the underlying database row is\n/// _not_ NULL. This can cause issues when your field type is an `Option<T>` because this would be\n/// represented as the _not_ NULL (in terms of DB) JSON value of `null`.\n///\n/// If you wish to describe a database row which _is_ NULLable but _cannot_ contain the JSON value `null`,\n/// use the `#[sqlx(json(nullable))]` attribute.\n///\n/// For example\n/// ```rust,ignore\n/// #[derive(serde::Deserialize)]\n/// struct Data {\n///     field1: String,\n///     field2: u64\n/// }\n///\n/// #[derive(sqlx::FromRow)]\n/// struct User {\n///     id: i32,\n///     name: String,\n///     #[sqlx(json(nullable))]\n///     metadata: Option<Data>\n/// }\n/// ```\n/// Would describe a database field which _is_ NULLable but if it exists it must be the JSON representation of `Data`\n/// and cannot be the JSON value `null`\n///\n/// ## Manual implementation\n///\n/// You can also implement the [`FromRow`] trait by hand. This can be useful if you\n/// have a struct with a field that needs manual decoding:\n///\n///\n/// ```rust,ignore\n/// use sqlx::{FromRow, sqlite::SqliteRow, sqlx::Row};\n/// struct MyCustomType {\n///     custom: String,\n/// }\n///\n/// struct Foo {\n///     bar: MyCustomType,\n/// }\n///\n/// impl FromRow<'_, SqliteRow> for Foo {\n///     fn from_row(row: &SqliteRow) -> sqlx::Result<Self> {\n///         Ok(Self {\n///             bar: MyCustomType {\n///                 custom: row.try_get(\"custom\")?\n///             }\n///         })\n///     }\n/// }\n/// ```\npub trait FromRow<'r, R: Row>: Sized {\n    fn from_row(row: &'r R) -> Result<Self, Error>;\n}\n\nimpl<'r, R> FromRow<'r, R> for ()\nwhere\n    R: Row,\n{\n    #[inline]\n    fn from_row(_: &'r R) -> Result<Self, Error> {\n        Ok(())\n    }\n}\n\n// implement FromRow for tuples of types that implement Decode\n// up to tuples of 16 values\n\nmacro_rules! impl_from_row_for_tuple {\n    ($( ($idx:tt) -> $T:ident );+;) => {\n        impl<'r, R, $($T,)+> FromRow<'r, R> for ($($T,)+)\n        where\n            R: Row,\n            usize: crate::column::ColumnIndex<R>,\n            $($T: crate::decode::Decode<'r, R::Database> + crate::types::Type<R::Database>,)+\n        {\n            #[inline]\n            fn from_row(row: &'r R) -> Result<Self, Error> {\n                Ok(($(row.try_get($idx as usize)?,)+))\n            }\n        }\n    };\n}\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n    (10) -> T11;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n    (10) -> T11;\n    (11) -> T12;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n    (10) -> T11;\n    (11) -> T12;\n    (12) -> T13;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n    (10) -> T11;\n    (11) -> T12;\n    (12) -> T13;\n    (13) -> T14;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n    (10) -> T11;\n    (11) -> T12;\n    (12) -> T13;\n    (13) -> T14;\n    (14) -> T15;\n);\n\nimpl_from_row_for_tuple!(\n    (0) -> T1;\n    (1) -> T2;\n    (2) -> T3;\n    (3) -> T4;\n    (4) -> T5;\n    (5) -> T6;\n    (6) -> T7;\n    (7) -> T8;\n    (8) -> T9;\n    (9) -> T10;\n    (10) -> T11;\n    (11) -> T12;\n    (12) -> T13;\n    (13) -> T14;\n    (14) -> T15;\n    (15) -> T16;\n);\n"
  },
  {
    "path": "sqlx-core/src/fs.rs",
    "content": "use std::ffi::OsString;\nuse std::fs::Metadata;\nuse std::io;\nuse std::path::{Path, PathBuf};\n\nuse crate::rt;\n\npub struct ReadDir {\n    inner: Option<std::fs::ReadDir>,\n}\n\npub struct DirEntry {\n    pub path: PathBuf,\n    pub file_name: OsString,\n    pub metadata: Metadata,\n}\n\n// Filesystem operations are generally not capable of being non-blocking\n// so Tokio and async-std don't bother; they just send the work to a blocking thread pool.\n//\n// We save on code duplication here by just implementing the same strategy ourselves\n// using the runtime's `spawn_blocking()` primitive.\n\npub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {\n    let path = PathBuf::from(path.as_ref());\n    rt::spawn_blocking(move || std::fs::read(path)).await\n}\n\npub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {\n    let path = PathBuf::from(path.as_ref());\n    rt::spawn_blocking(move || std::fs::read_to_string(path)).await\n}\n\npub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {\n    let path = PathBuf::from(path.as_ref());\n    rt::spawn_blocking(move || std::fs::create_dir_all(path)).await\n}\n\npub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {\n    let path = PathBuf::from(path.as_ref());\n    rt::spawn_blocking(move || std::fs::remove_file(path)).await\n}\n\npub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {\n    let path = PathBuf::from(path.as_ref());\n    rt::spawn_blocking(move || std::fs::remove_dir(path)).await\n}\n\npub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {\n    let path = PathBuf::from(path.as_ref());\n    rt::spawn_blocking(move || std::fs::remove_dir_all(path)).await\n}\n\npub async fn read_dir(path: PathBuf) -> io::Result<ReadDir> {\n    let read_dir = rt::spawn_blocking(move || std::fs::read_dir(path)).await?;\n\n    Ok(ReadDir {\n        inner: Some(read_dir),\n    })\n}\n\nimpl ReadDir {\n    pub async fn next(&mut self) -> io::Result<Option<DirEntry>> {\n        if let Some(mut read_dir) = self.inner.take() {\n            let maybe = rt::spawn_blocking(move || {\n                let entry = read_dir.next().transpose()?;\n\n                entry\n                    .map(|entry| -> io::Result<_> {\n                        Ok((\n                            read_dir,\n                            DirEntry {\n                                path: entry.path(),\n                                file_name: entry.file_name(),\n                                // We always want the metadata as well so might as well fetch\n                                // it in the same blocking call.\n                                metadata: entry.metadata()?,\n                            },\n                        ))\n                    })\n                    .transpose()\n            })\n            .await?;\n\n            match maybe {\n                Some((read_dir, entry)) => {\n                    self.inner = Some(read_dir);\n                    Ok(Some(entry))\n                }\n                None => Ok(None),\n            }\n        } else {\n            Ok(None)\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/io/buf.rs",
    "content": "use std::str::from_utf8;\n\nuse bytes::{Buf, Bytes};\nuse memchr::memchr;\n\nuse crate::error::Error;\n\npub trait BufExt: Buf {\n    // Read a nul-terminated byte sequence\n    fn get_bytes_nul(&mut self) -> Result<Bytes, Error>;\n\n    // Read a byte sequence of the exact length\n    fn get_bytes(&mut self, len: usize) -> Bytes;\n\n    // Read a nul-terminated string\n    fn get_str_nul(&mut self) -> Result<String, Error>;\n\n    // Read a string of the exact length\n    fn get_str(&mut self, len: usize) -> Result<String, Error>;\n}\n\nimpl BufExt for Bytes {\n    fn get_bytes_nul(&mut self) -> Result<Bytes, Error> {\n        let nul =\n            memchr(b'\\0', self).ok_or_else(|| err_protocol!(\"expected NUL in byte sequence\"))?;\n\n        let v = self.slice(0..nul);\n\n        self.advance(nul + 1);\n\n        Ok(v)\n    }\n\n    fn get_bytes(&mut self, len: usize) -> Bytes {\n        let v = self.slice(..len);\n        self.advance(len);\n\n        v\n    }\n\n    fn get_str_nul(&mut self) -> Result<String, Error> {\n        self.get_bytes_nul().and_then(|bytes| {\n            from_utf8(&bytes)\n                .map(ToOwned::to_owned)\n                .map_err(|err| err_protocol!(\"{}\", err))\n        })\n    }\n\n    fn get_str(&mut self, len: usize) -> Result<String, Error> {\n        let v = from_utf8(&self[..len])\n            .map_err(|err| err_protocol!(\"{}\", err))\n            .map(ToOwned::to_owned)?;\n\n        self.advance(len);\n\n        Ok(v)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/io/buf_mut.rs",
    "content": "use bytes::BufMut;\n\npub trait BufMutExt: BufMut {\n    fn put_str_nul(&mut self, s: &str);\n}\n\nimpl BufMutExt for Vec<u8> {\n    fn put_str_nul(&mut self, s: &str) {\n        self.extend(s.as_bytes());\n        self.push(0);\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/io/buf_stream.rs",
    "content": "#![allow(dead_code)]\n\nuse std::io;\nuse std::ops::{Deref, DerefMut};\n\nuse bytes::BytesMut;\nuse sqlx_rt::{AsyncRead, AsyncReadExt, AsyncWrite};\n\nuse crate::error::Error;\nuse crate::io::write_and_flush::WriteAndFlush;\nuse crate::io::{decode::Decode, encode::Encode};\nuse std::io::Cursor;\n\npub struct BufStream<S>\nwhere\n    S: AsyncRead + AsyncWrite + Unpin,\n{\n    pub(crate) stream: S,\n\n    // writes with `write` to the underlying stream are buffered\n    // this can be flushed with `flush`\n    pub(crate) wbuf: Vec<u8>,\n\n    // we read into the read buffer using 100% safe code\n    rbuf: BytesMut,\n}\n\nimpl<S> BufStream<S>\nwhere\n    S: AsyncRead + AsyncWrite + Unpin,\n{\n    pub fn new(stream: S) -> Self {\n        Self {\n            stream,\n            wbuf: Vec::with_capacity(512),\n            rbuf: BytesMut::with_capacity(4096),\n        }\n    }\n\n    pub fn write<'en, T>(&mut self, value: T)\n    where\n        T: Encode<'en, ()>,\n    {\n        self.write_with(value, ())\n    }\n\n    pub fn write_with<'en, T, C>(&mut self, value: T, context: C)\n    where\n        T: Encode<'en, C>,\n    {\n        value.encode_with(&mut self.wbuf, context);\n    }\n\n    pub fn flush(&mut self) -> WriteAndFlush<'_, S> {\n        WriteAndFlush {\n            stream: &mut self.stream,\n            buf: Cursor::new(&mut self.wbuf),\n        }\n    }\n\n    pub async fn read<'de, T>(&mut self, cnt: usize) -> Result<T, Error>\n    where\n        T: Decode<'de, ()>,\n    {\n        self.read_with(cnt, ()).await\n    }\n\n    pub async fn read_with<'de, T, C>(&mut self, cnt: usize, context: C) -> Result<T, Error>\n    where\n        T: Decode<'de, C>,\n    {\n        T::decode_with(self.read_raw(cnt).await?.freeze(), context)\n    }\n\n    pub async fn read_raw(&mut self, cnt: usize) -> Result<BytesMut, Error> {\n        read_raw_into(&mut self.stream, &mut self.rbuf, cnt).await?;\n        let buf = self.rbuf.split_to(cnt);\n\n        Ok(buf)\n    }\n\n    pub async fn read_raw_into(&mut self, buf: &mut BytesMut, cnt: usize) -> Result<(), Error> {\n        read_raw_into(&mut self.stream, buf, cnt).await\n    }\n}\n\nimpl<S> Deref for BufStream<S>\nwhere\n    S: AsyncRead + AsyncWrite + Unpin,\n{\n    type Target = S;\n\n    fn deref(&self) -> &Self::Target {\n        &self.stream\n    }\n}\n\nimpl<S> DerefMut for BufStream<S>\nwhere\n    S: AsyncRead + AsyncWrite + Unpin,\n{\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.stream\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/io/decode.rs",
    "content": "use bytes::Bytes;\n\nuse crate::error::Error;\n\npub trait ProtocolDecode<'de, Context = ()>\nwhere\n    Self: Sized,\n{\n    fn decode(buf: Bytes) -> Result<Self, Error>\n    where\n        Self: ProtocolDecode<'de, ()>,\n    {\n        Self::decode_with(buf, ())\n    }\n\n    fn decode_with(buf: Bytes, context: Context) -> Result<Self, Error>;\n}\n\nimpl ProtocolDecode<'_> for Bytes {\n    fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {\n        Ok(buf)\n    }\n}\n\nimpl ProtocolDecode<'_> for () {\n    fn decode_with(_: Bytes, _: ()) -> Result<(), Error> {\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/io/encode.rs",
    "content": "pub trait ProtocolEncode<'en, Context = ()> {\n    fn encode(&self, buf: &mut Vec<u8>) -> Result<(), crate::Error>\n    where\n        Self: ProtocolEncode<'en, ()>,\n    {\n        self.encode_with(buf, ())\n    }\n\n    fn encode_with(&self, buf: &mut Vec<u8>, context: Context) -> Result<(), crate::Error>;\n}\n\nimpl<C> ProtocolEncode<'_, C> for &'_ [u8] {\n    fn encode_with(&self, buf: &mut Vec<u8>, _context: C) -> Result<(), crate::Error> {\n        buf.extend_from_slice(self);\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/io/mod.rs",
    "content": "mod buf;\nmod buf_mut;\n// mod buf_stream;\nmod decode;\nmod encode;\nmod read_buf;\n// mod write_and_flush;\n\npub use buf::BufExt;\npub use buf_mut::BufMutExt;\n//pub use buf_stream::BufStream;\npub use decode::ProtocolDecode;\npub use encode::ProtocolEncode;\npub use read_buf::ReadBuf;\n\n#[cfg(not(feature = \"_rt-tokio\"))]\npub use futures_io::AsyncRead;\n\n#[cfg(feature = \"_rt-tokio\")]\npub use tokio::io::AsyncRead;\n\n#[cfg(not(feature = \"_rt-tokio\"))]\npub use futures_util::io::AsyncReadExt;\n\n#[cfg(feature = \"_rt-tokio\")]\npub use tokio::io::AsyncReadExt;\n"
  },
  {
    "path": "sqlx-core/src/io/read_buf.rs",
    "content": "use bytes::{BufMut, BytesMut};\n\n/// An extension for [`BufMut`] for getting a writeable buffer in safe code.\npub trait ReadBuf: BufMut {\n    /// Get the full capacity of this buffer as a safely initialized slice.\n    fn init_mut(&mut self) -> &mut [u8];\n}\n\nimpl ReadBuf for &'_ mut [u8] {\n    #[inline(always)]\n    fn init_mut(&mut self) -> &mut [u8] {\n        self\n    }\n}\n\nimpl ReadBuf for BytesMut {\n    #[inline(always)]\n    fn init_mut(&mut self) -> &mut [u8] {\n        // `self.remaining_mut()` returns `usize::MAX - self.len()`\n        let remaining = self.capacity() - self.len();\n\n        // I'm hoping for most uses that this operation is elided by the optimizer.\n        self.put_bytes(0, remaining);\n\n        self\n    }\n}\n\n#[test]\nfn test_read_buf_bytes_mut() {\n    let mut buf = BytesMut::with_capacity(8);\n    buf.put_u32(0x12345678);\n\n    assert_eq!(buf.init_mut(), [0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0]);\n}\n"
  },
  {
    "path": "sqlx-core/src/io/write_and_flush.rs",
    "content": "use crate::error::Error;\nuse sqlx_rt::AsyncWrite;\nuse std::future::Future;\nuse std::io::{BufRead, Cursor};\nuse std::pin::Pin;\nuse std::task::{ready, Context, Poll};\n\n// Atomic operation that writes the full buffer to the stream, flushes the stream, and then\n// clears the buffer (even if either of the two previous operations failed).\npub struct WriteAndFlush<'a, S> {\n    pub(super) stream: &'a mut S,\n    pub(super) buf: Cursor<&'a mut Vec<u8>>,\n}\n\nimpl<S: AsyncWrite + Unpin> Future for WriteAndFlush<'_, S> {\n    type Output = Result<(), Error>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let Self {\n            ref mut stream,\n            ref mut buf,\n        } = *self;\n\n        loop {\n            let read = buf.fill_buf()?;\n\n            if !read.is_empty() {\n                let written = ready!(Pin::new(&mut *stream).poll_write(cx, read)?);\n                buf.consume(written);\n            } else {\n                break;\n            }\n        }\n\n        Pin::new(stream).poll_flush(cx).map_err(Error::Io)\n    }\n}\n\nimpl<'a, S> Drop for WriteAndFlush<'a, S> {\n    fn drop(&mut self) {\n        // clear the buffer regardless of whether the flush succeeded or not\n        self.buf.get_mut().clear();\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/lib.rs",
    "content": "//! Core of SQLx, the rust SQL toolkit.\n//!\n//! ### Note: Semver Exempt API\n//! The API of this crate is not meant for general use and does *not* follow Semantic Versioning.\n//! The only crate that follows Semantic Versioning in the project is the `sqlx` crate itself.\n//! If you are building a custom SQLx driver, you should pin an exact version for `sqlx-core` to\n//! avoid breakages:\n//!\n//! ```toml\n//! sqlx-core = { version = \"=0.6.2\" }\n//! ```\n//!\n//! And then make releases in lockstep with `sqlx-core`. We recommend all driver crates, in-tree\n//! or otherwise, use the same version numbers as `sqlx-core` to avoid confusion.\n#![recursion_limit = \"512\"]\n#![warn(future_incompatible, rust_2018_idioms)]\n#![allow(clippy::needless_doctest_main, clippy::type_complexity)]\n// The only unsafe code in SQLx is that necessary to interact with native APIs like with SQLite,\n// and that can live in its own separate driver crate.\n#![forbid(unsafe_code)]\n// Allows an API be documented as only available in some specific platforms.\n// <https://doc.rust-lang.org/unstable-book/language-features/doc-cfg.html>\n#![cfg_attr(docsrs, feature(doc_cfg))]\n\n#[macro_use]\npub mod ext;\n\n#[macro_use]\npub mod error;\n\n#[macro_use]\npub mod arguments;\n\n#[macro_use]\npub mod pool;\n\npub mod connection;\n\n#[macro_use]\npub mod transaction;\n\n#[macro_use]\npub mod encode;\n\n#[macro_use]\npub mod decode;\n\n#[macro_use]\npub mod types;\n\n#[macro_use]\npub mod query;\n\n#[macro_use]\npub mod acquire;\n\n#[macro_use]\npub mod column;\n\n#[macro_use]\npub mod statement;\n\npub mod common;\npub mod database;\npub mod describe;\npub mod executor;\npub mod from_row;\npub mod fs;\npub mod io;\npub mod logger;\npub mod net;\npub mod query_as;\npub mod query_builder;\npub mod query_scalar;\npub mod sql_str;\n\npub mod raw_sql;\npub mod row;\npub mod rt;\npub mod sync;\npub mod type_checking;\npub mod type_info;\npub mod value;\n\n#[cfg(feature = \"migrate\")]\npub mod migrate;\n\n#[cfg(feature = \"any\")]\npub mod any;\n\n// Implements test support with automatic DB management.\n#[cfg(feature = \"migrate\")]\npub mod testing;\n\npub mod config;\n\npub use error::{Error, Result};\n\npub use either::Either;\npub use hashbrown::{hash_map, HashMap};\npub use indexmap::IndexMap;\npub use percent_encoding;\npub use smallvec::SmallVec;\npub use url::{self, Url};\n\npub use bytes;\n\n/// Helper module to get drivers compiling again that used to be in this crate,\n/// to avoid having to replace tons of `use crate::<...>` imports.\n///\n/// This module can be glob-imported and should not clash with any modules a driver\n/// would want to implement itself.\npub mod driver_prelude {\n    pub use crate::{\n        acquire, common, decode, describe, encode, executor, ext, from_row, fs, io, logger, net,\n        pool, query, query_as, query_builder, query_scalar, rt, sync,\n    };\n\n    pub use crate::error::{Error, Result};\n    pub use crate::{hash_map, HashMap};\n    pub use either::Either;\n}\n"
  },
  {
    "path": "sqlx-core/src/logger.rs",
    "content": "use crate::{connection::LogSettings, sql_str::SqlStr};\nuse std::time::Instant;\n\n// Yes these look silly. `tracing` doesn't currently support dynamic levels\n// https://github.com/tokio-rs/tracing/issues/372\n#[doc(hidden)]\n#[macro_export]\nmacro_rules! private_tracing_dynamic_enabled {\n    (target: $target:expr, $level:expr) => {{\n        use ::tracing::Level;\n\n        match $level {\n            Level::ERROR => ::tracing::enabled!(target: $target, Level::ERROR),\n            Level::WARN => ::tracing::enabled!(target: $target, Level::WARN),\n            Level::INFO => ::tracing::enabled!(target: $target, Level::INFO),\n            Level::DEBUG => ::tracing::enabled!(target: $target, Level::DEBUG),\n            Level::TRACE => ::tracing::enabled!(target: $target, Level::TRACE),\n        }\n    }};\n    ($level:expr) => {{\n        $crate::private_tracing_dynamic_enabled!(target: module_path!(), $level)\n    }};\n}\n\n#[doc(hidden)]\n#[macro_export]\nmacro_rules! private_tracing_dynamic_event {\n    (target: $target:expr, $level:expr, $($args:tt)*) => {{\n        use ::tracing::Level;\n\n        match $level {\n            Level::ERROR => ::tracing::event!(target: $target, Level::ERROR, $($args)*),\n            Level::WARN => ::tracing::event!(target: $target, Level::WARN, $($args)*),\n            Level::INFO => ::tracing::event!(target: $target, Level::INFO, $($args)*),\n            Level::DEBUG => ::tracing::event!(target: $target, Level::DEBUG, $($args)*),\n            Level::TRACE => ::tracing::event!(target: $target, Level::TRACE, $($args)*),\n        }\n    }};\n}\n\n#[doc(hidden)]\npub fn private_level_filter_to_levels(\n    filter: log::LevelFilter,\n) -> Option<(tracing::Level, log::Level)> {\n    let tracing_level = match filter {\n        log::LevelFilter::Error => Some(tracing::Level::ERROR),\n        log::LevelFilter::Warn => Some(tracing::Level::WARN),\n        log::LevelFilter::Info => Some(tracing::Level::INFO),\n        log::LevelFilter::Debug => Some(tracing::Level::DEBUG),\n        log::LevelFilter::Trace => Some(tracing::Level::TRACE),\n        log::LevelFilter::Off => None,\n    };\n\n    tracing_level.zip(filter.to_level())\n}\n\npub(crate) fn private_level_filter_to_trace_level(\n    filter: log::LevelFilter,\n) -> Option<tracing::Level> {\n    private_level_filter_to_levels(filter).map(|(level, _)| level)\n}\n\npub struct QueryLogger {\n    sql: SqlStr,\n    rows_returned: u64,\n    rows_affected: u64,\n    start: Instant,\n    settings: LogSettings,\n}\n\nimpl QueryLogger {\n    pub fn new(sql: SqlStr, settings: LogSettings) -> Self {\n        Self {\n            sql,\n            rows_returned: 0,\n            rows_affected: 0,\n            start: Instant::now(),\n            settings,\n        }\n    }\n\n    pub fn increment_rows_returned(&mut self) {\n        self.rows_returned += 1;\n    }\n\n    pub fn increase_rows_affected(&mut self, n: u64) {\n        self.rows_affected += n;\n    }\n\n    pub fn sql(&self) -> &SqlStr {\n        &self.sql\n    }\n\n    pub fn finish(&self) {\n        let elapsed = self.start.elapsed();\n\n        let was_slow = elapsed >= self.settings.slow_statements_duration;\n\n        let lvl = if was_slow {\n            self.settings.slow_statements_level\n        } else {\n            self.settings.statements_level\n        };\n\n        if let Some((tracing_level, log_level)) = private_level_filter_to_levels(lvl) {\n            // The enabled level could be set from either tracing world or log world, so check both\n            // to see if logging should be enabled for our level\n            let log_is_enabled = log::log_enabled!(target: \"sqlx::query\", log_level)\n                || private_tracing_dynamic_enabled!(target: \"sqlx::query\", tracing_level);\n            if log_is_enabled {\n                let mut summary = parse_query_summary(self.sql.as_str());\n\n                let sql = if summary != self.sql.as_str() {\n                    summary.push_str(\" …\");\n                    format!(\"\\n\\n{}\\n\", self.sql.as_str())\n                } else {\n                    String::new()\n                };\n\n                if was_slow {\n                    private_tracing_dynamic_event!(\n                        target: \"sqlx::query\",\n                        tracing_level,\n                        summary,\n                        db.statement = sql,\n                        rows_affected = self.rows_affected,\n                        rows_returned = self.rows_returned,\n                        // Human-friendly - includes units (usually ms). Also kept for backward compatibility\n                        ?elapsed,\n                        // Search friendly - numeric\n                        elapsed_secs = elapsed.as_secs_f64(),\n                        // When logging to JSON, one can trigger alerts from the presence of this field.\n                        slow_threshold=?self.settings.slow_statements_duration,\n                        // Make sure to use \"slow\" in the message as that's likely\n                        // what people will grep for.\n                        \"slow statement: execution time exceeded alert threshold\"\n                    );\n                } else {\n                    private_tracing_dynamic_event!(\n                        target: \"sqlx::query\",\n                        tracing_level,\n                        summary,\n                        db.statement = sql,\n                        rows_affected = self.rows_affected,\n                        rows_returned = self.rows_returned,\n                        // Human-friendly - includes units (usually ms). Also kept for backward compatibility\n                        ?elapsed,\n                        // Search friendly - numeric\n                        elapsed_secs = elapsed.as_secs_f64(),\n                    );\n                }\n            }\n        }\n    }\n}\n\nimpl Drop for QueryLogger {\n    fn drop(&mut self) {\n        self.finish();\n    }\n}\n\npub fn parse_query_summary(sql: &str) -> String {\n    // For now, just take the first 4 words\n    sql.split_whitespace()\n        .take(4)\n        .collect::<Vec<&str>>()\n        .join(\" \")\n}\n"
  },
  {
    "path": "sqlx-core/src/migrate/error.rs",
    "content": "use crate::error::{BoxDynError, Error};\n\n#[derive(Debug, thiserror::Error)]\n#[non_exhaustive]\npub enum MigrateError {\n    #[error(\"while executing migrations: {0}\")]\n    Execute(#[from] Error),\n\n    #[error(\"while executing migration {1}: {0}\")]\n    ExecuteMigration(#[source] Error, i64),\n\n    #[error(\"while resolving migrations: {0}\")]\n    Source(#[source] BoxDynError),\n\n    #[error(\"migration {0} was previously applied but is missing in the resolved migrations\")]\n    VersionMissing(i64),\n\n    #[error(\"migration {0} was previously applied but has been modified\")]\n    VersionMismatch(i64),\n\n    #[error(\"migration {0} is not present in the migration source\")]\n    VersionNotPresent(i64),\n\n    #[error(\"migration {0} is older than the latest applied migration {1}\")]\n    VersionTooOld(i64, i64),\n\n    #[error(\"migration {0} is newer than the latest applied migration {1}\")]\n    VersionTooNew(i64, i64),\n\n    #[error(\"database driver does not support force-dropping a database (Only PostgreSQL)\")]\n    ForceNotSupported,\n\n    #[deprecated = \"migration types are now inferred\"]\n    #[error(\"cannot mix reversible migrations with simple migrations. All migrations should be reversible or simple migrations\")]\n    InvalidMixReversibleAndSimple,\n\n    // NOTE: this will only happen with a database that does not have transactional DDL (.e.g, MySQL or Oracle)\n    #[error(\n        \"migration {0} is partially applied; fix and remove row from `_sqlx_migrations` table\"\n    )]\n    Dirty(i64),\n\n    #[error(\"database driver does not support creation of schemas at migrate time: {0}\")]\n    CreateSchemasNotSupported(String),\n}\n"
  },
  {
    "path": "sqlx-core/src/migrate/migrate.rs",
    "content": "use crate::error::Error;\nuse crate::migrate::{AppliedMigration, MigrateError, Migration};\nuse futures_core::future::BoxFuture;\nuse std::future::Future;\nuse std::time::Duration;\n\npub trait MigrateDatabase {\n    // create database in url\n    // uses a maintenance database depending on driver\n    fn create_database(url: &str) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    // check if the database in url exists\n    // uses a maintenance database depending on driver\n    fn database_exists(url: &str) -> impl Future<Output = Result<bool, Error>> + Send + '_;\n\n    // drop database in url\n    // uses a maintenance database depending on driver\n    fn drop_database(url: &str) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    // force drop database in url\n    // uses a maintenance database depending on driver\n    fn force_drop_database(_url: &str) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        async { Err(MigrateError::ForceNotSupported)? }\n    }\n}\n\n// 'e = Executor\npub trait Migrate {\n    /// Create a database schema with the given name if it does not already exist.\n    fn create_schema_if_not_exists<'e>(\n        &'e mut self,\n        schema_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>>;\n\n    // ensure migrations table exists\n    // will create or migrate it if needed\n    fn ensure_migrations_table<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>>;\n\n    // Return the version on which the database is dirty or None otherwise.\n    // \"dirty\" means there is a partially applied migration that failed.\n    fn dirty_version<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Option<i64>, MigrateError>>;\n\n    // Return the ordered list of applied migrations\n    fn list_applied_migrations<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>>;\n\n    // Should acquire a database lock so that only one migration process\n    // can run at a time. [`Migrate`] will call this function before applying\n    // any migrations.\n    fn lock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>>;\n\n    // Should release the lock. [`Migrate`] will call this function after all\n    // migrations have been run.\n    fn unlock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>>;\n\n    // run SQL from migration in a DDL transaction\n    // insert new row to [_migrations] table on completion (success or failure)\n    // returns the time taking to run the migration SQL\n    fn apply<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>>;\n\n    // run a revert SQL from migration in a DDL transaction\n    // deletes the row in [_migrations] table with specified migration version on completion (success or failure)\n    // returns the time taking to run the migration SQL\n    fn revert<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>>;\n}\n"
  },
  {
    "path": "sqlx-core/src/migrate/migration.rs",
    "content": "use sha2::{Digest, Sha384};\nuse std::borrow::Cow;\n\nuse crate::sql_str::SqlStr;\n\nuse super::MigrationType;\n\n#[derive(Debug, Clone)]\npub struct Migration {\n    pub version: i64,\n    pub description: Cow<'static, str>,\n    pub migration_type: MigrationType,\n    pub sql: SqlStr,\n    pub checksum: Cow<'static, [u8]>,\n    pub no_tx: bool,\n}\n\nimpl Migration {\n    pub fn new(\n        version: i64,\n        description: Cow<'static, str>,\n        migration_type: MigrationType,\n        sql: SqlStr,\n        no_tx: bool,\n    ) -> Self {\n        let checksum = checksum(sql.as_str());\n\n        Self::with_checksum(\n            version,\n            description,\n            migration_type,\n            sql,\n            checksum.into(),\n            no_tx,\n        )\n    }\n\n    pub(crate) fn with_checksum(\n        version: i64,\n        description: Cow<'static, str>,\n        migration_type: MigrationType,\n        sql: SqlStr,\n        checksum: Cow<'static, [u8]>,\n        no_tx: bool,\n    ) -> Self {\n        Migration {\n            version,\n            description,\n            migration_type,\n            sql,\n            checksum,\n            no_tx,\n        }\n    }\n}\n\n#[derive(Debug, Clone)]\npub struct AppliedMigration {\n    pub version: i64,\n    pub checksum: Cow<'static, [u8]>,\n}\n\npub fn checksum(sql: &str) -> Vec<u8> {\n    Vec::from(Sha384::digest(sql).as_slice())\n}\n\npub fn checksum_fragments<'a>(fragments: impl Iterator<Item = &'a str>) -> Vec<u8> {\n    let mut digest = Sha384::new();\n\n    for fragment in fragments {\n        digest.update(fragment);\n    }\n\n    digest.finalize().to_vec()\n}\n\n#[test]\nfn fragments_checksum_equals_full_checksum() {\n    // Copied from `examples/postgres/axum-social-with-tests/migrations/3_comment.sql`\n    let sql = \"\\\n        \\u{FEFF}create table comment (\\r\\n\\\n            \\tcomment_id uuid primary key default gen_random_uuid(),\\r\\n\\\n            \\tpost_id uuid not null references post(post_id),\\r\\n\\\n            \\tuser_id uuid not null references \\\"user\\\"(user_id),\\r\\n\\\n            \\tcontent text not null,\\r\\n\\\n            \\tcreated_at timestamptz not null default now()\\r\\n\\\n        );\\r\\n\\\n        \\r\\n\\\n        create index on comment(post_id, created_at);\\r\\n\\\n    \";\n\n    // Should yield a string for each character\n    let fragments_checksum = checksum_fragments(sql.split(\"\"));\n    let full_checksum = checksum(sql);\n\n    assert_eq!(fragments_checksum, full_checksum);\n}\n"
  },
  {
    "path": "sqlx-core/src/migrate/migration_type.rs",
    "content": "use super::Migrator;\n\n/// Migration Type represents the type of migration\n#[derive(Debug, Copy, Clone, PartialEq)]\npub enum MigrationType {\n    /// Simple migration are single file migrations with no up / down queries\n    Simple,\n\n    /// ReversibleUp migrations represents the  add or update part of a reversible migrations\n    /// It is expected the every migration of this type will have a corresponding down file\n    ReversibleUp,\n\n    /// ReversibleDown migrations represents the  delete or downgrade part of a reversible migrations\n    /// It is expected the every migration of this type will have a corresponding up file\n    ReversibleDown,\n}\n\nimpl MigrationType {\n    pub fn from_filename(filename: &str) -> Self {\n        if filename.ends_with(MigrationType::ReversibleUp.suffix()) {\n            MigrationType::ReversibleUp\n        } else if filename.ends_with(MigrationType::ReversibleDown.suffix()) {\n            MigrationType::ReversibleDown\n        } else {\n            MigrationType::Simple\n        }\n    }\n\n    pub fn is_reversible(&self) -> bool {\n        match self {\n            MigrationType::Simple => false,\n            MigrationType::ReversibleUp => true,\n            MigrationType::ReversibleDown => true,\n        }\n    }\n\n    pub fn is_up_migration(&self) -> bool {\n        match self {\n            MigrationType::Simple => true,\n            MigrationType::ReversibleUp => true,\n            MigrationType::ReversibleDown => false,\n        }\n    }\n\n    pub fn is_down_migration(&self) -> bool {\n        match self {\n            MigrationType::Simple => false,\n            MigrationType::ReversibleUp => false,\n            MigrationType::ReversibleDown => true,\n        }\n    }\n\n    pub fn label(&self) -> &'static str {\n        match self {\n            MigrationType::Simple => \"migrate\",\n            MigrationType::ReversibleUp => \"migrate\",\n            MigrationType::ReversibleDown => \"revert\",\n        }\n    }\n\n    pub fn suffix(&self) -> &'static str {\n        match self {\n            MigrationType::Simple => \".sql\",\n            MigrationType::ReversibleUp => \".up.sql\",\n            MigrationType::ReversibleDown => \".down.sql\",\n        }\n    }\n\n    pub fn file_content(&self) -> &'static str {\n        match self {\n            MigrationType::Simple => \"-- Add migration script here\\n\",\n            MigrationType::ReversibleUp => \"-- Add up migration script here\\n\",\n            MigrationType::ReversibleDown => \"-- Add down migration script here\\n\",\n        }\n    }\n\n    #[deprecated = \"unused\"]\n    pub fn infer(migrator: &Migrator, reversible: bool) -> MigrationType {\n        match migrator.iter().last() {\n            Some(first_migration) => first_migration.migration_type,\n            None => {\n                if reversible {\n                    MigrationType::ReversibleUp\n                } else {\n                    MigrationType::Simple\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/migrate/migrator.rs",
    "content": "use crate::acquire::Acquire;\nuse crate::migrate::{AppliedMigration, Migrate, MigrateError, Migration, MigrationSource};\nuse std::borrow::Cow;\nuse std::collections::{HashMap, HashSet};\nuse std::ops::Deref;\nuse std::slice;\n\n/// A resolved set of migrations, ready to be run.\n///\n/// Can be constructed statically using `migrate!()` or at runtime using [`Migrator::new()`].\n#[derive(Debug)]\n// Forbids `migrate!()` from constructing this:\n// #[non_exhaustive]\npub struct Migrator {\n    // NOTE: these fields are semver-exempt and may be changed or removed in any future version.\n    // These have to be public for `migrate!()` to be able to initialize them in an implicitly\n    // const-promotable context. A `const fn` constructor isn't implicitly const-promotable.\n    #[doc(hidden)]\n    pub migrations: Cow<'static, [Migration]>,\n    #[doc(hidden)]\n    pub ignore_missing: bool,\n    #[doc(hidden)]\n    pub locking: bool,\n    #[doc(hidden)]\n    pub no_tx: bool,\n    #[doc(hidden)]\n    pub table_name: Cow<'static, str>,\n\n    #[doc(hidden)]\n    pub create_schemas: Cow<'static, [Cow<'static, str>]>,\n}\n\nimpl Migrator {\n    #[doc(hidden)]\n    pub const DEFAULT: Migrator = Migrator {\n        migrations: Cow::Borrowed(&[]),\n        ignore_missing: false,\n        no_tx: false,\n        locking: true,\n        table_name: Cow::Borrowed(\"_sqlx_migrations\"),\n        create_schemas: Cow::Borrowed(&[]),\n    };\n\n    /// Creates a new instance with the given source.\n    ///\n    /// # Examples\n    ///\n    /// ```rust,no_run\n    /// # use sqlx_core::migrate::MigrateError;\n    /// # fn main() -> Result<(), MigrateError> {\n    /// # sqlx::__rt::test_block_on(async move {\n    /// # use sqlx_core::migrate::Migrator;\n    /// use std::path::Path;\n    ///\n    /// // Read migrations from a local folder: ./migrations\n    /// let m = Migrator::new(Path::new(\"./migrations\")).await?;\n    /// # Ok(())\n    /// # })\n    /// # }\n    /// ```\n    /// See [MigrationSource] for details on structure of the `./migrations` directory.\n    pub async fn new<'s, S>(source: S) -> Result<Self, MigrateError>\n    where\n        S: MigrationSource<'s>,\n    {\n        Ok(Self {\n            migrations: Cow::Owned(source.resolve().await.map_err(MigrateError::Source)?),\n            ..Self::DEFAULT\n        })\n    }\n\n    /// Creates a new instance with the given migrations.\n    ///\n    ///\n    /// # Examples\n    ///\n    /// ```rust,no_run\n    /// use sqlx::{ SqlSafeStr, migrate::{Migration, MigrationType::*, Migrator}};\n    ///\n    /// // Define your migrations.\n    /// // You can also use include_str!(\"./xxx.sql\") instead of hard-coded SQL statements.\n    /// let migrations = vec![\n    ///     Migration::new(1, \"user\".into(), ReversibleUp, \"create table users ( ... )\".into_sql_str(), false),\n    ///     Migration::new(2, \"post\".into(), ReversibleUp, \"create table posts ( ... )\".into_sql_str(), false),\n    ///     // add more...\n    ///  ];\n    ///  let m = Migrator::with_migrations(migrations);\n    /// ```\n    pub fn with_migrations(mut migrations: Vec<Migration>) -> Self {\n        // Ensure that we are sorted by version in ascending order.\n        migrations.sort_by_key(|m| m.version);\n        Self {\n            migrations: Cow::Owned(migrations),\n            ..Self::DEFAULT\n        }\n    }\n\n    /// Override the name of the table used to track executed migrations.\n    ///\n    /// May be schema-qualified and/or contain quotes. Defaults to `_sqlx_migrations`.\n    ///\n    /// Potentially useful for multi-tenant databases.\n    ///\n    /// ### Warning: Potential Data Loss or Corruption!\n    /// Changing this option for a production database will likely result in data loss or corruption\n    /// as the migration machinery will no longer be aware of what migrations have been applied\n    /// and will attempt to re-run them.\n    ///\n    /// You should create the new table as a copy of the existing migrations table (with contents!),\n    /// and be sure all instances of your application have been migrated to the new\n    /// table before deleting the old one.\n    pub fn dangerous_set_table_name(&mut self, table_name: impl Into<Cow<'static, str>>) -> &Self {\n        self.table_name = table_name.into();\n        self\n    }\n\n    /// Add a schema name to be created if it does not already exist.\n    ///\n    /// May be used with [`Self::dangerous_set_table_name()`] to place the migrations table\n    /// in a new schema without requiring it to exist first.\n    ///\n    /// ### Note: Support Depends on Database\n    /// SQLite cannot create new schemas without attaching them to a database file,\n    /// the path of which must be specified separately in an [`ATTACH DATABASE`](https://www.sqlite.org/lang_attach.html) command.\n    pub fn create_schema(&mut self, schema_name: impl Into<Cow<'static, str>>) -> &Self {\n        self.create_schemas.to_mut().push(schema_name.into());\n        self\n    }\n\n    /// Specify whether applied migrations that are missing from the resolved migrations should be ignored.\n    pub fn set_ignore_missing(&mut self, ignore_missing: bool) -> &mut Self {\n        self.ignore_missing = ignore_missing;\n        self\n    }\n\n    /// Specify whether or not to lock the database during migration. Defaults to `true`.\n    ///\n    /// ### Warning\n    /// Disabling locking can lead to errors or data loss if multiple clients attempt to apply migrations simultaneously\n    /// without some sort of mutual exclusion.\n    ///\n    /// This should only be used if the database does not support locking, e.g. CockroachDB which talks the Postgres\n    /// protocol but does not support advisory locks used by SQLx's migrations support for Postgres.\n    pub fn set_locking(&mut self, locking: bool) -> &mut Self {\n        self.locking = locking;\n        self\n    }\n\n    /// Get an iterator over all known migrations.\n    pub fn iter(&self) -> slice::Iter<'_, Migration> {\n        self.migrations.iter()\n    }\n\n    /// Check if a migration version exists.\n    pub fn version_exists(&self, version: i64) -> bool {\n        self.iter().any(|m| m.version == version)\n    }\n\n    /// Run any pending migrations against the database; and, validate previously applied migrations\n    /// against the current migration source to detect accidental changes in previously-applied migrations.\n    ///\n    /// # Examples\n    ///\n    /// ```rust,no_run\n    /// # use sqlx::migrate::MigrateError;\n    /// # fn main() -> Result<(), MigrateError> {\n    /// #     sqlx::__rt::test_block_on(async move {\n    /// use sqlx::migrate::Migrator;\n    /// use sqlx::sqlite::SqlitePoolOptions;\n    ///\n    /// let m = Migrator::new(std::path::Path::new(\"./migrations\")).await?;\n    /// let pool = SqlitePoolOptions::new().connect(\"sqlite::memory:\").await?;\n    /// m.run(&pool).await\n    /// #     })\n    /// # }\n    /// ```\n    pub async fn run<'a, A>(&self, migrator: A) -> Result<(), MigrateError>\n    where\n        A: Acquire<'a>,\n        <A::Connection as Deref>::Target: Migrate,\n    {\n        let mut conn = migrator.acquire().await?;\n        self.run_direct(None, &mut *conn).await\n    }\n\n    pub async fn run_to<'a, A>(&self, target: i64, migrator: A) -> Result<(), MigrateError>\n    where\n        A: Acquire<'a>,\n        <A::Connection as Deref>::Target: Migrate,\n    {\n        let mut conn = migrator.acquire().await?;\n        self.run_direct(Some(target), &mut *conn).await\n    }\n\n    // Getting around the annoying \"implementation of `Acquire` is not general enough\" error\n    #[doc(hidden)]\n    pub async fn run_direct<C>(&self, target: Option<i64>, conn: &mut C) -> Result<(), MigrateError>\n    where\n        C: Migrate,\n    {\n        // lock the database for exclusive access by the migrator\n        if self.locking {\n            conn.lock().await?;\n        }\n\n        for schema_name in self.create_schemas.iter() {\n            conn.create_schema_if_not_exists(schema_name).await?;\n        }\n\n        // creates [_migrations] table only if needed\n        // eventually this will likely migrate previous versions of the table\n        conn.ensure_migrations_table(&self.table_name).await?;\n\n        let version = conn.dirty_version(&self.table_name).await?;\n        if let Some(version) = version {\n            return Err(MigrateError::Dirty(version));\n        }\n\n        let applied_migrations = conn.list_applied_migrations(&self.table_name).await?;\n        validate_applied_migrations(&applied_migrations, self)?;\n\n        let applied_migrations: HashMap<_, _> = applied_migrations\n            .into_iter()\n            .map(|m| (m.version, m))\n            .collect();\n\n        for migration in self.iter() {\n            if target.is_some_and(|target| target < migration.version) {\n                // Target version reached\n                break;\n            }\n\n            if migration.migration_type.is_down_migration() {\n                continue;\n            }\n\n            match applied_migrations.get(&migration.version) {\n                Some(applied_migration) => {\n                    if migration.checksum != applied_migration.checksum {\n                        return Err(MigrateError::VersionMismatch(migration.version));\n                    }\n                }\n                None => {\n                    conn.apply(&self.table_name, migration).await?;\n                }\n            }\n        }\n\n        // unlock the migrator to allow other migrators to run\n        // but do nothing as we already migrated\n        if self.locking {\n            conn.unlock().await?;\n        }\n\n        Ok(())\n    }\n\n    /// Run down migrations against the database until a specific version.\n    ///\n    /// # Examples\n    ///\n    /// ```rust,no_run\n    /// # use sqlx::migrate::MigrateError;\n    /// # fn main() -> Result<(), MigrateError> {\n    /// #     sqlx::__rt::test_block_on(async move {\n    /// use sqlx::migrate::Migrator;\n    /// use sqlx::sqlite::SqlitePoolOptions;\n    ///\n    /// let m = Migrator::new(std::path::Path::new(\"./migrations\")).await?;\n    /// let pool = SqlitePoolOptions::new().connect(\"sqlite::memory:\").await?;\n    /// m.undo(&pool, 4).await\n    /// #     })\n    /// # }\n    /// ```\n    pub async fn undo<'a, A>(&self, migrator: A, target: i64) -> Result<(), MigrateError>\n    where\n        A: Acquire<'a>,\n        <A::Connection as Deref>::Target: Migrate,\n    {\n        let mut conn = migrator.acquire().await?;\n\n        // lock the database for exclusive access by the migrator\n        if self.locking {\n            conn.lock().await?;\n        }\n\n        // creates [_migrations] table only if needed\n        // eventually this will likely migrate previous versions of the table\n        conn.ensure_migrations_table(&self.table_name).await?;\n\n        let version = conn.dirty_version(&self.table_name).await?;\n        if let Some(version) = version {\n            return Err(MigrateError::Dirty(version));\n        }\n\n        let applied_migrations = conn.list_applied_migrations(&self.table_name).await?;\n        validate_applied_migrations(&applied_migrations, self)?;\n\n        let applied_migrations: HashMap<_, _> = applied_migrations\n            .into_iter()\n            .map(|m| (m.version, m))\n            .collect();\n\n        for migration in self\n            .iter()\n            .rev()\n            .filter(|m| m.migration_type.is_down_migration())\n            .filter(|m| applied_migrations.contains_key(&m.version))\n            .filter(|m| m.version > target)\n        {\n            conn.revert(&self.table_name, migration).await?;\n        }\n\n        // unlock the migrator to allow other migrators to run\n        // but do nothing as we already migrated\n        if self.locking {\n            conn.unlock().await?;\n        }\n\n        Ok(())\n    }\n}\n\nfn validate_applied_migrations(\n    applied_migrations: &[AppliedMigration],\n    migrator: &Migrator,\n) -> Result<(), MigrateError> {\n    if migrator.ignore_missing {\n        return Ok(());\n    }\n\n    let migrations: HashSet<_> = migrator.iter().map(|m| m.version).collect();\n\n    for applied_migration in applied_migrations {\n        if !migrations.contains(&applied_migration.version) {\n            return Err(MigrateError::VersionMissing(applied_migration.version));\n        }\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-core/src/migrate/mod.rs",
    "content": "mod error;\n#[allow(clippy::module_inception)]\nmod migrate;\nmod migration;\nmod migration_type;\nmod migrator;\nmod source;\n\npub use error::MigrateError;\npub use migrate::{Migrate, MigrateDatabase};\npub use migration::{AppliedMigration, Migration};\npub use migration_type::MigrationType;\npub use migrator::Migrator;\npub use source::{MigrationSource, ResolveConfig, ResolveWith};\n\n#[doc(hidden)]\npub use source::{resolve_blocking, resolve_blocking_with_config};\n"
  },
  {
    "path": "sqlx-core/src/migrate/source.rs",
    "content": "use crate::error::BoxDynError;\nuse crate::migrate::{migration, Migration, MigrationType};\nuse crate::sql_str::{AssertSqlSafe, SqlSafeStr};\nuse futures_core::future::BoxFuture;\n\nuse std::borrow::Cow;\nuse std::collections::BTreeSet;\nuse std::fmt::Debug;\nuse std::fs;\nuse std::io;\nuse std::path::{Path, PathBuf};\n\n/// In the default implementation, a MigrationSource is a directory which\n/// contains the migration SQL scripts. All these scripts must be stored in\n/// files with names using the format `<VERSION>_<DESCRIPTION>.sql`, where\n/// `<VERSION>` is a string that can be parsed into `i64` and its value is\n/// greater than zero, and `<DESCRIPTION>` is a string.\n///\n/// Files that don't match this format are silently ignored.\n///\n/// You can create a new empty migration script using sqlx-cli:\n/// `sqlx migrate add <DESCRIPTION>`.\n///\n/// Note that migrations for each database are tracked using the\n/// `_sqlx_migrations` table (stored in the database). If a migration's hash\n/// changes and it has already been run, this will cause an error.\npub trait MigrationSource<'s>: Debug {\n    fn resolve(self) -> BoxFuture<'s, Result<Vec<Migration>, BoxDynError>>;\n}\n\nimpl<'s> MigrationSource<'s> for &'s Path {\n    fn resolve(self) -> BoxFuture<'s, Result<Vec<Migration>, BoxDynError>> {\n        // Behavior changed from previous because `canonicalize()` is potentially blocking\n        // since it might require going to disk to fetch filesystem data.\n        self.to_owned().resolve()\n    }\n}\n\nimpl MigrationSource<'static> for PathBuf {\n    fn resolve(self) -> BoxFuture<'static, Result<Vec<Migration>, BoxDynError>> {\n        // Technically this could just be `Box::pin(spawn_blocking(...))`\n        // but that would actually be a breaking behavior change because it would call\n        // `spawn_blocking()` on the current thread\n        Box::pin(async move {\n            crate::rt::spawn_blocking(move || {\n                let migrations_with_paths = resolve_blocking(&self)?;\n\n                Ok(migrations_with_paths.into_iter().map(|(m, _p)| m).collect())\n            })\n            .await\n        })\n    }\n}\n\n/// A [`MigrationSource`] implementation with configurable resolution.\n///\n/// `S` may be `PathBuf`, `&Path` or any type that implements `Into<PathBuf>`.\n///\n/// See [`ResolveConfig`] for details.\n#[derive(Debug)]\npub struct ResolveWith<S>(pub S, pub ResolveConfig);\n\nimpl<'s, S: Debug + Into<PathBuf> + Send + 's> MigrationSource<'s> for ResolveWith<S> {\n    fn resolve(self) -> BoxFuture<'s, Result<Vec<Migration>, BoxDynError>> {\n        Box::pin(async move {\n            let path = self.0.into();\n            let config = self.1;\n\n            let migrations_with_paths =\n                crate::rt::spawn_blocking(move || resolve_blocking_with_config(&path, &config))\n                    .await?;\n\n            Ok(migrations_with_paths.into_iter().map(|(m, _p)| m).collect())\n        })\n    }\n}\n\n#[derive(thiserror::Error, Debug)]\n#[error(\"{message}\")]\npub struct ResolveError {\n    message: String,\n    #[source]\n    source: Option<io::Error>,\n}\n\n/// Configuration for migration resolution using [`ResolveWith`].\n#[derive(Debug, Default)]\npub struct ResolveConfig {\n    ignored_chars: BTreeSet<char>,\n}\n\nimpl ResolveConfig {\n    /// Return a default, empty configuration.\n    pub fn new() -> Self {\n        ResolveConfig {\n            ignored_chars: BTreeSet::new(),\n        }\n    }\n\n    /// Ignore a character when hashing migrations.\n    ///\n    /// The migration SQL string itself will still contain the character,\n    /// but it will not be included when calculating the checksum.\n    ///\n    /// This can be used to ignore whitespace characters so changing formatting\n    /// does not change the checksum.\n    ///\n    /// Adding the same `char` more than once is a no-op.\n    ///\n    /// ### Note: Changes Migration Checksum\n    /// This will change the checksum of resolved migrations,\n    /// which may cause problems with existing deployments.\n    ///\n    /// **Use at your own risk.**\n    pub fn ignore_char(&mut self, c: char) -> &mut Self {\n        self.ignored_chars.insert(c);\n        self\n    }\n\n    /// Ignore one or more characters when hashing migrations.\n    ///\n    /// The migration SQL string itself will still contain these characters,\n    /// but they will not be included when calculating the checksum.\n    ///\n    /// This can be used to ignore whitespace characters so changing formatting\n    /// does not change the checksum.\n    ///\n    /// Adding the same `char` more than once is a no-op.\n    ///\n    /// ### Note: Changes Migration Checksum\n    /// This will change the checksum of resolved migrations,\n    /// which may cause problems with existing deployments.\n    ///\n    /// **Use at your own risk.**\n    pub fn ignore_chars(&mut self, chars: impl IntoIterator<Item = char>) -> &mut Self {\n        self.ignored_chars.extend(chars);\n        self\n    }\n\n    /// Iterate over the set of ignored characters.\n    ///\n    /// Duplicate `char`s are not included.\n    pub fn ignored_chars(&self) -> impl Iterator<Item = char> + '_ {\n        self.ignored_chars.iter().copied()\n    }\n}\n\n// FIXME: paths should just be part of `Migration` but we can't add a field backwards compatibly\n// since it's `#[non_exhaustive]`.\n#[doc(hidden)]\npub fn resolve_blocking(path: &Path) -> Result<Vec<(Migration, PathBuf)>, ResolveError> {\n    resolve_blocking_with_config(path, &ResolveConfig::new())\n}\n\n#[doc(hidden)]\npub fn resolve_blocking_with_config(\n    path: &Path,\n    config: &ResolveConfig,\n) -> Result<Vec<(Migration, PathBuf)>, ResolveError> {\n    let path = path.canonicalize().map_err(|e| ResolveError {\n        message: format!(\"error canonicalizing path {}\", path.display()),\n        source: Some(e),\n    })?;\n\n    let s = fs::read_dir(&path).map_err(|e| ResolveError {\n        message: format!(\"error reading migration directory {}\", path.display()),\n        source: Some(e),\n    })?;\n\n    let mut migrations = Vec::new();\n\n    for res in s {\n        let entry = res.map_err(|e| ResolveError {\n            message: format!(\n                \"error reading contents of migration directory {}\",\n                path.display()\n            ),\n            source: Some(e),\n        })?;\n\n        let entry_path = entry.path();\n\n        let metadata = fs::metadata(&entry_path).map_err(|e| ResolveError {\n            message: format!(\n                \"error getting metadata of migration path {}\",\n                entry_path.display()\n            ),\n            source: Some(e),\n        })?;\n\n        if !metadata.is_file() {\n            // not a file; ignore\n            continue;\n        }\n\n        let file_name = entry.file_name();\n        // This is arguably the wrong choice,\n        // but it really only matters for parsing the version and description.\n        //\n        // Using `.to_str()` and returning an error if the filename is not UTF-8\n        // would be a breaking change.\n        let file_name = file_name.to_string_lossy();\n\n        let parts = file_name.splitn(2, '_').collect::<Vec<_>>();\n\n        if parts.len() != 2 || !parts[1].ends_with(\".sql\") {\n            // not of the format: <VERSION>_<DESCRIPTION>.<REVERSIBLE_DIRECTION>.sql; ignore\n            continue;\n        }\n\n        let version: i64 = parts[0].parse()\n            .map_err(|_e| ResolveError {\n                message: format!(\"error parsing migration filename {file_name:?}; expected integer version prefix (e.g. `01_foo.sql`)\"),\n                source: None,\n            })?;\n\n        let migration_type = MigrationType::from_filename(parts[1]);\n\n        // remove the `.sql` and replace `_` with ` `\n        let description = parts[1]\n            .trim_end_matches(migration_type.suffix())\n            .replace('_', \" \")\n            .to_owned();\n\n        let sql = fs::read_to_string(&entry_path).map_err(|e| ResolveError {\n            message: format!(\n                \"error reading contents of migration {}: {e}\",\n                entry_path.display()\n            ),\n            source: Some(e),\n        })?;\n\n        // opt-out of migration transaction\n        let no_tx = sql.starts_with(\"-- no-transaction\");\n\n        let checksum = checksum_with(&sql, &config.ignored_chars);\n\n        migrations.push((\n            Migration::with_checksum(\n                version,\n                Cow::Owned(description),\n                migration_type,\n                AssertSqlSafe(sql).into_sql_str(),\n                checksum.into(),\n                no_tx,\n            ),\n            entry_path,\n        ));\n    }\n\n    // Ensure that we are sorted by version in ascending order.\n    migrations.sort_by_key(|(m, _)| m.version);\n\n    Ok(migrations)\n}\n\nfn checksum_with(sql: &str, ignored_chars: &BTreeSet<char>) -> Vec<u8> {\n    if ignored_chars.is_empty() {\n        // This is going to be much faster because it doesn't have to UTF-8 decode `sql`.\n        return migration::checksum(sql);\n    }\n\n    migration::checksum_fragments(sql.split(|c| ignored_chars.contains(&c)))\n}\n\n#[test]\nfn checksum_with_ignored_chars() {\n    // Ensure that `checksum_with` returns the same digest for a given set of ignored chars\n    // as the equivalent string with the characters removed.\n    let ignored_chars = [\n        ' ', '\\t', '\\r', '\\n',\n        // Zero-width non-breaking space (ZWNBSP), often added as a magic-number at the beginning\n        // of UTF-8 encoded files as a byte-order mark (BOM):\n        // https://en.wikipedia.org/wiki/Byte_order_mark\n        '\\u{FEFF}',\n    ];\n\n    // Copied from `examples/postgres/axum-social-with-tests/migrations/3_comment.sql`\n    let sql = \"\\\n        \\u{FEFF}create table comment (\\r\\n\\\n            \\tcomment_id uuid primary key default gen_random_uuid(),\\r\\n\\\n            \\tpost_id uuid not null references post(post_id),\\r\\n\\\n            \\tuser_id uuid not null references \\\"user\\\"(user_id),\\r\\n\\\n            \\tcontent text not null,\\r\\n\\\n            \\tcreated_at timestamptz not null default now()\\r\\n\\\n        );\\r\\n\\\n        \\r\\n\\\n        create index on comment(post_id, created_at);\\r\\n\\\n    \";\n\n    let stripped_sql = sql.replace(&ignored_chars[..], \"\");\n\n    let ignored_chars = BTreeSet::from(ignored_chars);\n\n    let digest_ignored = checksum_with(sql, &ignored_chars);\n    let digest_stripped = migration::checksum(&stripped_sql);\n\n    assert_eq!(digest_ignored, digest_stripped);\n}\n"
  },
  {
    "path": "sqlx-core/src/net/mod.rs",
    "content": "mod socket;\npub mod tls;\n\npub use socket::{\n    connect_tcp, connect_uds, BufferedSocket, Socket, SocketIntoBox, WithSocket, WriteBuffer,\n};\n"
  },
  {
    "path": "sqlx-core/src/net/socket/buffered.rs",
    "content": "use crate::error::Error;\nuse crate::net::Socket;\nuse bytes::BytesMut;\nuse std::ops::ControlFlow;\nuse std::{cmp, io};\n\nuse crate::io::{AsyncRead, AsyncReadExt, ProtocolDecode, ProtocolEncode};\n\n// Tokio, async-std, and std all use this as the default capacity for their buffered I/O.\nconst DEFAULT_BUF_SIZE: usize = 8192;\n\npub struct BufferedSocket<S> {\n    socket: S,\n    write_buf: WriteBuffer,\n    read_buf: ReadBuffer,\n}\n\npub struct WriteBuffer {\n    buf: Vec<u8>,\n    bytes_written: usize,\n    bytes_flushed: usize,\n}\n\npub struct ReadBuffer {\n    read: BytesMut,\n    available: BytesMut,\n}\n\nimpl<S: Socket> BufferedSocket<S> {\n    pub fn new(socket: S) -> Self\n    where\n        S: Sized,\n    {\n        BufferedSocket {\n            socket,\n            write_buf: WriteBuffer {\n                buf: Vec::with_capacity(DEFAULT_BUF_SIZE),\n                bytes_written: 0,\n                bytes_flushed: 0,\n            },\n            read_buf: ReadBuffer {\n                read: BytesMut::new(),\n                available: BytesMut::with_capacity(DEFAULT_BUF_SIZE),\n            },\n        }\n    }\n\n    pub async fn read_buffered(&mut self, len: usize) -> Result<BytesMut, Error> {\n        self.try_read(|buf| {\n            Ok(if buf.len() < len {\n                ControlFlow::Continue(len)\n            } else {\n                ControlFlow::Break(buf.split_to(len))\n            })\n        })\n        .await\n    }\n\n    /// Retryable read operation.\n    ///\n    /// The callback should check the contents of the buffer passed to it and either:\n    ///\n    /// * Remove a full message from the buffer and return [`ControlFlow::Break`], or:\n    /// * Return [`ControlFlow::Continue`] with the expected _total_ length of the buffer,\n    ///   _without_ modifying it.\n    ///\n    /// Cancel-safe as long as the callback does not modify the passed `BytesMut`\n    /// before returning [`ControlFlow::Continue`].\n    pub async fn try_read<F, R>(&mut self, mut try_read: F) -> Result<R, Error>\n    where\n        F: FnMut(&mut BytesMut) -> Result<ControlFlow<R, usize>, Error>,\n    {\n        loop {\n            let read_len = match try_read(&mut self.read_buf.read)? {\n                ControlFlow::Continue(read_len) => read_len,\n                ControlFlow::Break(ret) => return Ok(ret),\n            };\n\n            self.read_buf.read(read_len, &mut self.socket).await?;\n        }\n    }\n\n    pub fn write_buffer(&self) -> &WriteBuffer {\n        &self.write_buf\n    }\n\n    pub fn write_buffer_mut(&mut self) -> &mut WriteBuffer {\n        &mut self.write_buf\n    }\n\n    pub async fn read<'de, T>(&mut self, byte_len: usize) -> Result<T, Error>\n    where\n        T: ProtocolDecode<'de, ()>,\n    {\n        self.read_with(byte_len, ()).await\n    }\n\n    pub async fn read_with<'de, T, C>(&mut self, byte_len: usize, context: C) -> Result<T, Error>\n    where\n        T: ProtocolDecode<'de, C>,\n    {\n        T::decode_with(self.read_buffered(byte_len).await?.freeze(), context)\n    }\n\n    #[inline(always)]\n    pub fn write<'en, T>(&mut self, value: T) -> Result<(), Error>\n    where\n        T: ProtocolEncode<'en, ()>,\n    {\n        self.write_with(value, ())\n    }\n\n    #[inline(always)]\n    pub fn write_with<'en, T, C>(&mut self, value: T, context: C) -> Result<(), Error>\n    where\n        T: ProtocolEncode<'en, C>,\n    {\n        value.encode_with(self.write_buf.buf_mut(), context)?;\n        self.write_buf.bytes_written = self.write_buf.buf.len();\n        self.write_buf.sanity_check();\n\n        Ok(())\n    }\n\n    pub async fn flush(&mut self) -> io::Result<()> {\n        while !self.write_buf.is_empty() {\n            let written = self.socket.write(self.write_buf.get()).await?;\n            self.write_buf.consume(written);\n            self.write_buf.sanity_check();\n        }\n\n        self.socket.flush().await?;\n\n        Ok(())\n    }\n\n    pub async fn shutdown(&mut self) -> io::Result<()> {\n        self.flush().await?;\n        self.socket.shutdown().await\n    }\n\n    pub fn shrink_buffers(&mut self) {\n        // Won't drop data still in the buffer.\n        self.write_buf.shrink();\n        self.read_buf.shrink();\n    }\n\n    pub fn into_inner(self) -> S {\n        self.socket\n    }\n\n    pub fn boxed(self) -> BufferedSocket<Box<dyn Socket>> {\n        BufferedSocket {\n            socket: Box::new(self.socket),\n            write_buf: self.write_buf,\n            read_buf: self.read_buf,\n        }\n    }\n}\n\nimpl WriteBuffer {\n    fn sanity_check(&self) {\n        assert_ne!(self.buf.capacity(), 0);\n        assert!(self.bytes_written <= self.buf.len());\n        assert!(self.bytes_flushed <= self.bytes_written);\n    }\n\n    pub fn buf_mut(&mut self) -> &mut Vec<u8> {\n        self.buf.truncate(self.bytes_written);\n        self.sanity_check();\n        &mut self.buf\n    }\n\n    pub fn init_remaining_mut(&mut self) -> &mut [u8] {\n        self.buf.resize(self.buf.capacity(), 0);\n        self.sanity_check();\n        &mut self.buf[self.bytes_written..]\n    }\n\n    pub fn put_slice(&mut self, slice: &[u8]) {\n        // If we already have an initialized area that can fit the slice,\n        // don't change `self.buf.len()`\n        if let Some(dest) = self.buf[self.bytes_written..].get_mut(..slice.len()) {\n            dest.copy_from_slice(slice);\n        } else {\n            self.buf.truncate(self.bytes_written);\n            self.buf.extend_from_slice(slice);\n        }\n        self.advance(slice.len());\n        self.sanity_check();\n    }\n\n    pub fn advance(&mut self, amt: usize) {\n        let new_bytes_written = self\n            .bytes_written\n            .checked_add(amt)\n            .expect(\"self.bytes_written + amt overflowed\");\n\n        assert!(new_bytes_written <= self.buf.len());\n\n        self.bytes_written = new_bytes_written;\n\n        self.sanity_check();\n    }\n\n    /// Read into the buffer from `source`, returning the number of bytes read.\n    ///\n    /// The buffer is automatically advanced by the number of bytes read.\n    pub async fn read_from(&mut self, mut source: impl AsyncRead + Unpin) -> io::Result<usize> {\n        let read = match () {\n            // Tokio lets us read into the buffer without zeroing first\n            #[cfg(feature = \"_rt-tokio\")]\n            _ => source.read_buf(self.buf_mut()).await?,\n            #[cfg(not(feature = \"_rt-tokio\"))]\n            _ => source.read(self.init_remaining_mut()).await?,\n        };\n\n        if read > 0 {\n            self.advance(read);\n        }\n\n        Ok(read)\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.bytes_flushed >= self.bytes_written\n    }\n\n    pub fn is_full(&self) -> bool {\n        self.bytes_written == self.buf.len()\n    }\n\n    pub fn get(&self) -> &[u8] {\n        &self.buf[self.bytes_flushed..self.bytes_written]\n    }\n\n    pub fn get_mut(&mut self) -> &mut [u8] {\n        &mut self.buf[self.bytes_flushed..self.bytes_written]\n    }\n\n    pub fn shrink(&mut self) {\n        if self.bytes_flushed > 0 {\n            // Move any data that remains to be flushed to the beginning of the buffer,\n            // if necessary.\n            self.buf\n                .copy_within(self.bytes_flushed..self.bytes_written, 0);\n            self.bytes_written -= self.bytes_flushed;\n            self.bytes_flushed = 0\n        }\n\n        // Drop excess capacity.\n        self.buf\n            .truncate(cmp::max(self.bytes_written, DEFAULT_BUF_SIZE));\n        self.buf.shrink_to_fit();\n    }\n\n    fn consume(&mut self, amt: usize) {\n        let new_bytes_flushed = self\n            .bytes_flushed\n            .checked_add(amt)\n            .expect(\"self.bytes_flushed + amt overflowed\");\n\n        assert!(new_bytes_flushed <= self.bytes_written);\n\n        self.bytes_flushed = new_bytes_flushed;\n\n        if self.bytes_flushed == self.bytes_written {\n            // Reset cursors to zero if we've consumed the whole buffer\n            self.bytes_flushed = 0;\n            self.bytes_written = 0;\n        }\n\n        self.sanity_check();\n    }\n}\n\nimpl ReadBuffer {\n    async fn read(&mut self, len: usize, socket: &mut impl Socket) -> io::Result<()> {\n        // Because of how `BytesMut` works, we should only be shifting capacity back and forth\n        // between `read` and `available` unless we have to read an oversize message.\n        while self.read.len() < len {\n            self.reserve(len - self.read.len());\n\n            let read = socket.read(&mut self.available).await?;\n\n            if read == 0 {\n                return Err(io::Error::new(\n                    io::ErrorKind::UnexpectedEof,\n                    format!(\n                        \"expected to read {} bytes, got {} bytes at EOF\",\n                        len,\n                        self.read.len()\n                    ),\n                ));\n            }\n\n            self.advance(read);\n        }\n\n        Ok(())\n    }\n\n    fn reserve(&mut self, amt: usize) {\n        if let Some(additional) = amt.checked_sub(self.available.capacity()) {\n            self.available.reserve(additional);\n        }\n    }\n\n    fn advance(&mut self, amt: usize) {\n        self.read.unsplit(self.available.split_to(amt));\n    }\n\n    fn shrink(&mut self) {\n        if self.available.capacity() > DEFAULT_BUF_SIZE {\n            // `BytesMut` doesn't have a way to shrink its capacity,\n            // but we only use `available` for spare capacity anyway so we can just replace it.\n            //\n            // If `self.read` still contains data on the next call to `advance` then this might\n            // force a memcpy as they'll no longer be pointing to the same allocation,\n            // but that's kind of unavoidable.\n            //\n            // The `async-std` impl of `Socket` will also need to re-zero the buffer,\n            // but that's also kind of unavoidable.\n            //\n            // We should be warning the user not to call this often.\n            self.available = BytesMut::with_capacity(DEFAULT_BUF_SIZE);\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/net/socket/mod.rs",
    "content": "use std::future::Future;\nuse std::io;\nuse std::path::Path;\nuse std::pin::Pin;\nuse std::task::{ready, Context, Poll};\n\npub use buffered::{BufferedSocket, WriteBuffer};\nuse bytes::BufMut;\nuse cfg_if::cfg_if;\n\nuse crate::io::ReadBuf;\n\nmod buffered;\n\npub trait Socket: Send + Sync + Unpin + 'static {\n    fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize>;\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize>;\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>>;\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>>;\n\n    fn poll_flush(&mut self, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        // `flush()` is a no-op for TCP/UDS\n        Poll::Ready(Ok(()))\n    }\n\n    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>>;\n\n    fn read<'a, B: ReadBuf>(&'a mut self, buf: &'a mut B) -> Read<'a, Self, B>\n    where\n        Self: Sized,\n    {\n        Read { socket: self, buf }\n    }\n\n    fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self>\n    where\n        Self: Sized,\n    {\n        Write { socket: self, buf }\n    }\n\n    fn flush(&mut self) -> Flush<'_, Self>\n    where\n        Self: Sized,\n    {\n        Flush { socket: self }\n    }\n\n    fn shutdown(&mut self) -> Shutdown<'_, Self>\n    where\n        Self: Sized,\n    {\n        Shutdown { socket: self }\n    }\n}\n\npub struct Read<'a, S: ?Sized, B> {\n    socket: &'a mut S,\n    buf: &'a mut B,\n}\n\nimpl<S: ?Sized, B> Future for Read<'_, S, B>\nwhere\n    S: Socket,\n    B: ReadBuf,\n{\n    type Output = io::Result<usize>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = &mut *self;\n\n        while this.buf.has_remaining_mut() {\n            match this.socket.try_read(&mut *this.buf) {\n                Err(e) if e.kind() == io::ErrorKind::WouldBlock => {\n                    ready!(this.socket.poll_read_ready(cx))?;\n                }\n                ready => return Poll::Ready(ready),\n            }\n        }\n\n        Poll::Ready(Ok(0))\n    }\n}\n\npub struct Write<'a, S: ?Sized> {\n    socket: &'a mut S,\n    buf: &'a [u8],\n}\n\nimpl<S: ?Sized> Future for Write<'_, S>\nwhere\n    S: Socket,\n{\n    type Output = io::Result<usize>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        let this = &mut *self;\n\n        while !this.buf.is_empty() {\n            match this.socket.try_write(this.buf) {\n                Err(e) if e.kind() == io::ErrorKind::WouldBlock => {\n                    ready!(this.socket.poll_write_ready(cx))?;\n                }\n                ready => return Poll::Ready(ready),\n            }\n        }\n\n        Poll::Ready(Ok(0))\n    }\n}\n\npub struct Flush<'a, S: ?Sized> {\n    socket: &'a mut S,\n}\n\nimpl<S: Socket + ?Sized> Future for Flush<'_, S> {\n    type Output = io::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.socket.poll_flush(cx)\n    }\n}\n\npub struct Shutdown<'a, S: ?Sized> {\n    socket: &'a mut S,\n}\n\nimpl<S: ?Sized> Future for Shutdown<'_, S>\nwhere\n    S: Socket,\n{\n    type Output = io::Result<()>;\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        self.socket.poll_shutdown(cx)\n    }\n}\n\npub trait WithSocket {\n    type Output;\n\n    fn with_socket<S: Socket>(self, socket: S) -> impl Future<Output = Self::Output> + Send;\n}\n\npub struct SocketIntoBox;\n\nimpl WithSocket for SocketIntoBox {\n    type Output = Box<dyn Socket>;\n\n    async fn with_socket<S: Socket>(self, socket: S) -> Self::Output {\n        Box::new(socket)\n    }\n}\n\nimpl<S: Socket + ?Sized> Socket for Box<S> {\n    fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        (**self).try_read(buf)\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        (**self).try_write(buf)\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (**self).poll_read_ready(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (**self).poll_write_ready(cx)\n    }\n\n    fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (**self).poll_flush(cx)\n    }\n\n    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (**self).poll_shutdown(cx)\n    }\n}\n\npub async fn connect_tcp<Ws: WithSocket>(\n    host: &str,\n    port: u16,\n    with_socket: Ws,\n) -> crate::Result<Ws::Output> {\n    #[cfg(feature = \"_rt-tokio\")]\n    if crate::rt::rt_tokio::available() {\n        return Ok(with_socket\n            .with_socket(tokio::net::TcpStream::connect((host, port)).await?)\n            .await);\n    }\n\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-io\")] {\n            Ok(with_socket.with_socket(connect_tcp_async_io(host, port).await?).await)\n        } else {\n            crate::rt::missing_rt((host, port, with_socket))\n        }\n    }\n}\n\n/// Open a TCP socket to `host` and `port`.\n///\n/// If `host` is a hostname, attempt to connect to each address it resolves to.\n///\n/// This implements the same behavior as [`tokio::net::TcpStream::connect()`].\n#[cfg(feature = \"_rt-async-io\")]\nasync fn connect_tcp_async_io(host: &str, port: u16) -> crate::Result<impl Socket> {\n    use async_io::Async;\n    use std::net::{IpAddr, TcpStream, ToSocketAddrs};\n\n    // IPv6 addresses in URLs will be wrapped in brackets and the `url` crate doesn't trim those.\n    let host = host.trim_matches(&['[', ']'][..]);\n\n    if let Ok(addr) = host.parse::<IpAddr>() {\n        return Ok(Async::<TcpStream>::connect((addr, port)).await?);\n    }\n\n    let host = host.to_string();\n\n    let addresses = crate::rt::spawn_blocking(move || {\n        let addr = (host.as_str(), port);\n        ToSocketAddrs::to_socket_addrs(&addr)\n    })\n    .await?;\n\n    let mut last_err = None;\n\n    // Loop through all the Socket Addresses that the hostname resolves to\n    for socket_addr in addresses {\n        match Async::<TcpStream>::connect(socket_addr).await {\n            Ok(stream) => return Ok(stream),\n            Err(e) => last_err = Some(e),\n        }\n    }\n\n    // If we reach this point, it means we failed to connect to any of the addresses.\n    // Return the last error we encountered, or a custom error if the hostname didn't resolve to any address.\n    Err(last_err\n        .unwrap_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::AddrNotAvailable,\n                \"Hostname did not resolve to any addresses\",\n            )\n        })\n        .into())\n}\n\n/// Connect a Unix Domain Socket at the given path.\n///\n/// Returns an error if Unix Domain Sockets are not supported on this platform.\npub async fn connect_uds<P: AsRef<Path>, Ws: WithSocket>(\n    path: P,\n    with_socket: Ws,\n) -> crate::Result<Ws::Output> {\n    #[cfg(unix)]\n    {\n        #[cfg(feature = \"_rt-tokio\")]\n        if crate::rt::rt_tokio::available() {\n            use tokio::net::UnixStream;\n\n            let stream = UnixStream::connect(path).await?;\n\n            return Ok(with_socket.with_socket(stream).await);\n        }\n\n        cfg_if! {\n            if #[cfg(feature = \"_rt-async-io\")] {\n                use async_io::Async;\n                use std::os::unix::net::UnixStream;\n\n                let stream = Async::<UnixStream>::connect(path).await?;\n\n                Ok(with_socket.with_socket(stream).await)\n            } else {\n                crate::rt::missing_rt((path, with_socket))\n            }\n        }\n    }\n\n    #[cfg(not(unix))]\n    {\n        drop((path, with_socket));\n\n        Err(io::Error::new(\n            io::ErrorKind::Unsupported,\n            \"Unix domain sockets are not supported on this platform\",\n        )\n        .into())\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/net/tls/mod.rs",
    "content": "#![allow(dead_code)]\n\nuse std::path::PathBuf;\n\nuse crate::error::Error;\nuse crate::net::socket::WithSocket;\nuse crate::net::Socket;\n\n#[cfg(feature = \"_tls-rustls\")]\nmod tls_rustls;\n\n#[cfg(feature = \"_tls-native-tls\")]\nmod tls_native_tls;\n\nmod util;\n\n/// X.509 Certificate input, either a file path or a PEM encoded inline certificate(s).\n#[derive(Clone, Debug)]\npub enum CertificateInput {\n    /// PEM encoded certificate(s)\n    Inline(Vec<u8>),\n    /// Path to a file containing PEM encoded certificate(s)\n    File(PathBuf),\n}\n\nimpl From<String> for CertificateInput {\n    fn from(value: String) -> Self {\n        // Leading and trailing whitespace/newlines\n        let trimmed = value.trim();\n\n        // Heuristic for PEM encoded inputs:\n        // https://tools.ietf.org/html/rfc7468\n        if trimmed.starts_with(\"-----BEGIN\") && trimmed.ends_with(\"-----\") {\n            CertificateInput::Inline(value.as_bytes().to_vec())\n        } else {\n            CertificateInput::File(PathBuf::from(value))\n        }\n    }\n}\n\nimpl CertificateInput {\n    async fn data(&self) -> Result<Vec<u8>, std::io::Error> {\n        use crate::fs;\n        match self {\n            CertificateInput::Inline(v) => Ok(v.clone()),\n            CertificateInput::File(path) => fs::read(path).await,\n        }\n    }\n}\n\nimpl std::fmt::Display for CertificateInput {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        match self {\n            CertificateInput::Inline(v) => write!(f, \"{}\", String::from_utf8_lossy(v.as_slice())),\n            CertificateInput::File(path) => write!(f, \"file: {}\", path.display()),\n        }\n    }\n}\n\npub struct TlsConfig<'a> {\n    pub accept_invalid_certs: bool,\n    pub accept_invalid_hostnames: bool,\n    pub hostname: &'a str,\n    pub root_cert_path: Option<&'a CertificateInput>,\n    pub client_cert_path: Option<&'a CertificateInput>,\n    pub client_key_path: Option<&'a CertificateInput>,\n}\n\npub async fn handshake<S, Ws>(\n    socket: S,\n    config: TlsConfig<'_>,\n    with_socket: Ws,\n) -> crate::Result<Ws::Output>\nwhere\n    S: Socket,\n    Ws: WithSocket,\n{\n    #[cfg(feature = \"_tls-native-tls\")]\n    return Ok(with_socket\n        .with_socket(tls_native_tls::handshake(socket, config).await?)\n        .await);\n\n    #[cfg(all(feature = \"_tls-rustls\", not(feature = \"_tls-native-tls\")))]\n    return Ok(with_socket\n        .with_socket(tls_rustls::handshake(socket, config).await?)\n        .await);\n\n    #[cfg(not(any(feature = \"_tls-native-tls\", feature = \"_tls-rustls\")))]\n    {\n        drop((socket, config, with_socket));\n        panic!(\"one of the `runtime-*-native-tls` or `runtime-*-rustls` features must be enabled\")\n    }\n}\n\npub fn available() -> bool {\n    cfg!(any(feature = \"_tls-native-tls\", feature = \"_tls-rustls\"))\n}\n\npub fn error_if_unavailable() -> crate::Result<()> {\n    if !available() {\n        return Err(Error::tls(\n            \"TLS upgrade required by connect options \\\n                    but SQLx was built without TLS support enabled\",\n        ));\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-core/src/net/tls/tls_native_tls.rs",
    "content": "use std::io::{self, Read, Write};\n\nuse crate::io::ReadBuf;\nuse crate::net::tls::util::StdSocket;\nuse crate::net::tls::TlsConfig;\nuse crate::net::Socket;\nuse crate::rt;\nuse crate::Error;\n\nuse native_tls::{HandshakeError, Identity};\nuse std::task::{Context, Poll};\n\npub struct NativeTlsSocket<S: Socket> {\n    stream: native_tls::TlsStream<StdSocket<S>>,\n}\n\nimpl<S: Socket> Socket for NativeTlsSocket<S> {\n    fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        self.stream.read(buf.init_mut())\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.stream.write(buf)\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.stream.get_mut().poll_ready(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.stream.get_mut().poll_ready(cx)\n    }\n\n    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        match self.stream.shutdown() {\n            Err(e) if e.kind() == io::ErrorKind::WouldBlock => self.stream.get_mut().poll_ready(cx),\n            ready => Poll::Ready(ready),\n        }\n    }\n}\n\npub async fn handshake<S: Socket>(\n    socket: S,\n    config: TlsConfig<'_>,\n) -> crate::Result<NativeTlsSocket<S>> {\n    let mut builder = native_tls::TlsConnector::builder();\n\n    builder\n        .danger_accept_invalid_certs(config.accept_invalid_certs)\n        .danger_accept_invalid_hostnames(config.accept_invalid_hostnames);\n\n    if let Some(root_cert_path) = config.root_cert_path {\n        let data = root_cert_path.data().await?;\n        builder.add_root_certificate(native_tls::Certificate::from_pem(&data).map_err(Error::tls)?);\n    }\n\n    // authentication using user's key-file and its associated certificate\n    if let (Some(cert_path), Some(key_path)) = (config.client_cert_path, config.client_key_path) {\n        let cert_path = cert_path.data().await?;\n        let key_path = key_path.data().await?;\n        let identity = Identity::from_pkcs8(&cert_path, &key_path).map_err(Error::tls)?;\n        builder.identity(identity);\n    }\n\n    // The openssl TlsConnector synchronously loads certificates from files.\n    // Loading these files can block for tens of milliseconds.\n    let connector = rt::spawn_blocking(move || builder.build())\n        .await\n        .map_err(Error::tls)?;\n\n    let mut mid_handshake = match connector.connect(config.hostname, StdSocket::new(socket)) {\n        Ok(tls_stream) => return Ok(NativeTlsSocket { stream: tls_stream }),\n        Err(HandshakeError::Failure(e)) => return Err(Error::tls(e)),\n        Err(HandshakeError::WouldBlock(mid_handshake)) => mid_handshake,\n    };\n\n    loop {\n        mid_handshake.get_mut().ready().await?;\n\n        match mid_handshake.handshake() {\n            Ok(tls_stream) => return Ok(NativeTlsSocket { stream: tls_stream }),\n            Err(HandshakeError::Failure(e)) => return Err(Error::tls(e)),\n            Err(HandshakeError::WouldBlock(mid_handshake_)) => {\n                mid_handshake = mid_handshake_;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/net/tls/tls_rustls.rs",
    "content": "use std::future;\nuse std::io::{self, Read, Write};\nuse std::sync::Arc;\nuse std::task::{ready, Context, Poll};\n\nuse rustls::{\n    client::{\n        danger::{ServerCertVerified, ServerCertVerifier},\n        WebPkiServerVerifier,\n    },\n    crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider},\n    pki_types::{\n        pem::{self, PemObject},\n        CertificateDer, PrivateKeyDer, ServerName, UnixTime,\n    },\n    CertificateError, ClientConfig, ClientConnection, Error as TlsError, RootCertStore,\n};\n\nuse crate::error::Error;\nuse crate::io::ReadBuf;\nuse crate::net::tls::util::StdSocket;\nuse crate::net::tls::TlsConfig;\nuse crate::net::Socket;\n\npub struct RustlsSocket<S: Socket> {\n    inner: StdSocket<S>,\n    state: ClientConnection,\n    close_notify_sent: bool,\n}\n\nimpl<S: Socket> RustlsSocket<S> {\n    fn poll_complete_io(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        loop {\n            match self.state.complete_io(&mut self.inner) {\n                Err(e) if e.kind() == io::ErrorKind::WouldBlock => {\n                    ready!(self.inner.poll_ready(cx))?;\n                }\n                ready => return Poll::Ready(ready.map(|_| ())),\n            }\n        }\n    }\n\n    async fn complete_io(&mut self) -> io::Result<()> {\n        future::poll_fn(|cx| self.poll_complete_io(cx)).await\n    }\n}\n\nimpl<S: Socket> Socket for RustlsSocket<S> {\n    fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        self.state.reader().read(buf.init_mut())\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        match self.state.writer().write(buf) {\n            // Returns a zero-length write when the buffer is full.\n            Ok(0) => Err(io::ErrorKind::WouldBlock.into()),\n            other => other,\n        }\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_complete_io(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_complete_io(cx)\n    }\n\n    fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_complete_io(cx)\n    }\n\n    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        if !self.close_notify_sent {\n            self.state.send_close_notify();\n            self.close_notify_sent = true;\n        }\n\n        ready!(self.poll_complete_io(cx))?;\n\n        // Server can close socket as soon as it receives the connection shutdown request.\n        // We shouldn't expect it to stick around for the TLS session to close cleanly.\n        // https://security.stackexchange.com/a/82034\n        let _ = ready!(self.inner.socket.poll_shutdown(cx));\n\n        Poll::Ready(Ok(()))\n    }\n}\n\npub async fn handshake<S>(socket: S, tls_config: TlsConfig<'_>) -> Result<RustlsSocket<S>, Error>\nwhere\n    S: Socket,\n{\n    #[cfg(all(\n        feature = \"_tls-rustls-aws-lc-rs\",\n        not(feature = \"_tls-rustls-ring-webpki\"),\n        not(feature = \"_tls-rustls-ring-native-roots\")\n    ))]\n    let provider = Arc::new(rustls::crypto::aws_lc_rs::default_provider());\n    #[cfg(any(\n        feature = \"_tls-rustls-ring-webpki\",\n        feature = \"_tls-rustls-ring-native-roots\"\n    ))]\n    let provider = Arc::new(rustls::crypto::ring::default_provider());\n\n    // Unwrapping is safe here because we use a default provider.\n    let config = ClientConfig::builder_with_provider(provider.clone())\n        .with_safe_default_protocol_versions()\n        .unwrap();\n\n    // authentication using user's key and its associated certificate\n    let user_auth = match (tls_config.client_cert_path, tls_config.client_key_path) {\n        (Some(cert_path), Some(key_path)) => {\n            let cert_chain = certs_from_pem(cert_path.data().await?)?;\n            let key_der = private_key_from_pem(key_path.data().await?)?;\n            Some((cert_chain, key_der))\n        }\n        (None, None) => None,\n        (_, _) => {\n            return Err(Error::Configuration(\n                \"user auth key and certs must be given together\".into(),\n            ))\n        }\n    };\n\n    let config = if tls_config.accept_invalid_certs {\n        if let Some(user_auth) = user_auth {\n            config\n                .dangerous()\n                .with_custom_certificate_verifier(Arc::new(DummyTlsVerifier { provider }))\n                .with_client_auth_cert(user_auth.0, user_auth.1)\n                .map_err(Error::tls)?\n        } else {\n            config\n                .dangerous()\n                .with_custom_certificate_verifier(Arc::new(DummyTlsVerifier { provider }))\n                .with_no_client_auth()\n        }\n    } else {\n        let mut cert_store = import_root_certs();\n\n        if let Some(ca) = tls_config.root_cert_path {\n            let data = ca.data().await?;\n\n            for result in CertificateDer::pem_slice_iter(&data) {\n                let Ok(cert) = result else {\n                    return Err(Error::Tls(format!(\"Invalid certificate {ca}\").into()));\n                };\n\n                cert_store.add(cert).map_err(|err| Error::Tls(err.into()))?;\n            }\n        }\n\n        if tls_config.accept_invalid_hostnames {\n            let verifier = WebPkiServerVerifier::builder(Arc::new(cert_store))\n                .build()\n                .map_err(|err| Error::Tls(err.into()))?;\n\n            if let Some(user_auth) = user_auth {\n                config\n                    .dangerous()\n                    .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier }))\n                    .with_client_auth_cert(user_auth.0, user_auth.1)\n                    .map_err(Error::tls)?\n            } else {\n                config\n                    .dangerous()\n                    .with_custom_certificate_verifier(Arc::new(NoHostnameTlsVerifier { verifier }))\n                    .with_no_client_auth()\n            }\n        } else if let Some(user_auth) = user_auth {\n            config\n                .with_root_certificates(cert_store)\n                .with_client_auth_cert(user_auth.0, user_auth.1)\n                .map_err(Error::tls)?\n        } else {\n            config\n                .with_root_certificates(cert_store)\n                .with_no_client_auth()\n        }\n    };\n\n    let host = ServerName::try_from(tls_config.hostname.to_owned()).map_err(Error::tls)?;\n\n    let mut socket = RustlsSocket {\n        inner: StdSocket::new(socket),\n        state: ClientConnection::new(Arc::new(config), host).map_err(Error::tls)?,\n        close_notify_sent: false,\n    };\n\n    // Performs the TLS handshake or bails\n    socket.complete_io().await?;\n\n    Ok(socket)\n}\n\nfn certs_from_pem(pem: Vec<u8>) -> Result<Vec<CertificateDer<'static>>, Error> {\n    CertificateDer::pem_slice_iter(&pem)\n        .map(|result| result.map_err(|err| Error::Tls(err.into())))\n        .collect()\n}\n\nfn private_key_from_pem(pem: Vec<u8>) -> Result<PrivateKeyDer<'static>, Error> {\n    match PrivateKeyDer::from_pem_slice(&pem) {\n        Ok(key) => Ok(key),\n        Err(pem::Error::NoItemsFound) => Err(Error::Configuration(\"no keys found pem file\".into())),\n        Err(e) => Err(Error::Configuration(e.to_string().into())),\n    }\n}\n\n#[cfg(all(feature = \"webpki-roots\", not(feature = \"rustls-native-certs\")))]\nfn import_root_certs() -> RootCertStore {\n    RootCertStore::from_iter(webpki_roots::TLS_SERVER_ROOTS.iter().cloned())\n}\n\n#[cfg(feature = \"rustls-native-certs\")]\nfn import_root_certs() -> RootCertStore {\n    let mut root_cert_store = RootCertStore::empty();\n\n    let load_results = rustls_native_certs::load_native_certs();\n    for e in load_results.errors {\n        log::warn!(\"Error loading native certificates: {e:?}\");\n    }\n    for cert in load_results.certs {\n        if let Err(e) = root_cert_store.add(cert) {\n            log::warn!(\"rustls failed to parse native certificate: {e:?}\");\n        }\n    }\n\n    root_cert_store\n}\n\n// Not currently used but allows for a \"tls-rustls-no-roots\" feature.\n#[cfg(not(any(feature = \"rustls-native-certs\", feature = \"webpki-roots\")))]\nfn import_root_certs() -> RootCertStore {\n    RootCertStore::empty()\n}\n\n#[derive(Debug)]\nstruct DummyTlsVerifier {\n    provider: Arc<CryptoProvider>,\n}\n\nimpl ServerCertVerifier for DummyTlsVerifier {\n    fn verify_server_cert(\n        &self,\n        _end_entity: &CertificateDer<'_>,\n        _intermediates: &[CertificateDer<'_>],\n        _server_name: &ServerName<'_>,\n        _ocsp_response: &[u8],\n        _now: UnixTime,\n    ) -> Result<ServerCertVerified, TlsError> {\n        Ok(ServerCertVerified::assertion())\n    }\n\n    fn verify_tls12_signature(\n        &self,\n        message: &[u8],\n        cert: &CertificateDer<'_>,\n        dss: &rustls::DigitallySignedStruct,\n    ) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {\n        verify_tls12_signature(\n            message,\n            cert,\n            dss,\n            &self.provider.signature_verification_algorithms,\n        )\n    }\n\n    fn verify_tls13_signature(\n        &self,\n        message: &[u8],\n        cert: &CertificateDer<'_>,\n        dss: &rustls::DigitallySignedStruct,\n    ) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {\n        verify_tls13_signature(\n            message,\n            cert,\n            dss,\n            &self.provider.signature_verification_algorithms,\n        )\n    }\n\n    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {\n        self.provider\n            .signature_verification_algorithms\n            .supported_schemes()\n    }\n}\n\n#[derive(Debug)]\npub struct NoHostnameTlsVerifier {\n    verifier: Arc<WebPkiServerVerifier>,\n}\n\nimpl ServerCertVerifier for NoHostnameTlsVerifier {\n    fn verify_server_cert(\n        &self,\n        end_entity: &CertificateDer<'_>,\n        intermediates: &[CertificateDer<'_>],\n        server_name: &ServerName<'_>,\n        ocsp_response: &[u8],\n        now: UnixTime,\n    ) -> Result<ServerCertVerified, TlsError> {\n        match self.verifier.verify_server_cert(\n            end_entity,\n            intermediates,\n            server_name,\n            ocsp_response,\n            now,\n        ) {\n            Err(TlsError::InvalidCertificate(\n                CertificateError::NotValidForName | CertificateError::NotValidForNameContext { .. },\n            )) => Ok(ServerCertVerified::assertion()),\n            res => res,\n        }\n    }\n\n    fn verify_tls12_signature(\n        &self,\n        message: &[u8],\n        cert: &CertificateDer<'_>,\n        dss: &rustls::DigitallySignedStruct,\n    ) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {\n        self.verifier.verify_tls12_signature(message, cert, dss)\n    }\n\n    fn verify_tls13_signature(\n        &self,\n        message: &[u8],\n        cert: &CertificateDer<'_>,\n        dss: &rustls::DigitallySignedStruct,\n    ) -> Result<rustls::client::danger::HandshakeSignatureValid, TlsError> {\n        self.verifier.verify_tls13_signature(message, cert, dss)\n    }\n\n    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {\n        self.verifier.supported_verify_schemes()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/net/tls/util.rs",
    "content": "use crate::net::Socket;\n\nuse std::future;\nuse std::io::{self, Read, Write};\nuse std::task::{ready, Context, Poll};\n\npub struct StdSocket<S> {\n    pub socket: S,\n    wants_read: bool,\n    wants_write: bool,\n}\n\nimpl<S: Socket> StdSocket<S> {\n    pub fn new(socket: S) -> Self {\n        Self {\n            socket,\n            wants_read: false,\n            wants_write: false,\n        }\n    }\n\n    pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        if self.wants_write {\n            ready!(self.socket.poll_write_ready(cx))?;\n            self.wants_write = false;\n        }\n\n        if self.wants_read {\n            ready!(self.socket.poll_read_ready(cx))?;\n            self.wants_read = false;\n        }\n\n        Poll::Ready(Ok(()))\n    }\n\n    pub async fn ready(&mut self) -> io::Result<()> {\n        future::poll_fn(|cx| self.poll_ready(cx)).await\n    }\n}\n\nimpl<S: Socket> Read for StdSocket<S> {\n    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {\n        self.wants_read = true;\n        let read = self.socket.try_read(&mut buf)?;\n        self.wants_read = false;\n\n        Ok(read)\n    }\n}\n\nimpl<S: Socket> Write for StdSocket<S> {\n    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.wants_write = true;\n        let written = self.socket.try_write(buf)?;\n        self.wants_write = false;\n        Ok(written)\n    }\n\n    fn flush(&mut self) -> io::Result<()> {\n        // NOTE: TCP sockets and unix sockets are both no-ops for flushes\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/pool/connection.rs",
    "content": "use std::fmt::{self, Debug, Formatter};\nuse std::future::{self, Future};\nuse std::ops::{Deref, DerefMut};\nuse std::sync::Arc;\nuse std::time::{Duration, Instant};\n\nuse crate::sync::AsyncSemaphoreReleaser;\n\nuse crate::connection::Connection;\nuse crate::database::Database;\nuse crate::error::Error;\n\nuse super::inner::{is_beyond_max_lifetime, DecrementSizeGuard, PoolInner};\nuse crate::pool::options::PoolConnectionMetadata;\n\nconst CLOSE_ON_DROP_TIMEOUT: Duration = Duration::from_secs(5);\n\n/// A connection managed by a [`Pool`][crate::pool::Pool].\n///\n/// Will be returned to the pool on-drop.\npub struct PoolConnection<DB: Database> {\n    live: Option<Live<DB>>,\n    close_on_drop: bool,\n    pub(crate) pool: Arc<PoolInner<DB>>,\n}\n\npub(super) struct Live<DB: Database> {\n    pub(super) raw: DB::Connection,\n    pub(super) created_at: Instant,\n}\n\npub(super) struct Idle<DB: Database> {\n    pub(super) live: Live<DB>,\n    pub(super) idle_since: Instant,\n}\n\n/// RAII wrapper for connections being handled by functions that may drop them\npub(super) struct Floating<DB: Database, C> {\n    pub(super) inner: C,\n    pub(super) guard: DecrementSizeGuard<DB>,\n}\n\nconst EXPECT_MSG: &str = \"BUG: inner connection already taken!\";\n\nimpl<DB: Database> Debug for PoolConnection<DB> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        // TODO: Show the type name of the connection ?\n        f.debug_struct(\"PoolConnection\").finish()\n    }\n}\n\nimpl<DB: Database> Deref for PoolConnection<DB> {\n    type Target = DB::Connection;\n\n    fn deref(&self) -> &Self::Target {\n        &self.live.as_ref().expect(EXPECT_MSG).raw\n    }\n}\n\nimpl<DB: Database> DerefMut for PoolConnection<DB> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.live.as_mut().expect(EXPECT_MSG).raw\n    }\n}\n\nimpl<DB: Database> AsRef<DB::Connection> for PoolConnection<DB> {\n    fn as_ref(&self) -> &DB::Connection {\n        self\n    }\n}\n\nimpl<DB: Database> AsMut<DB::Connection> for PoolConnection<DB> {\n    fn as_mut(&mut self) -> &mut DB::Connection {\n        self\n    }\n}\n\nimpl<DB: Database> PoolConnection<DB> {\n    /// Close this connection, allowing the pool to open a replacement.\n    ///\n    /// Equivalent to calling [`.detach()`] then [`.close()`], but the connection permit is retained\n    /// for the duration so that the pool may not exceed `max_connections`.\n    ///\n    /// [`.detach()`]: PoolConnection::detach\n    /// [`.close()`]: Connection::close\n    pub async fn close(mut self) -> Result<(), Error> {\n        let floating = self.take_live().float(self.pool.clone());\n        floating.inner.raw.close().await\n    }\n\n    /// Close this connection on-drop, instead of returning it to the pool.\n    ///\n    /// May be used in cases where waiting for the [`.close()`][Self::close] call\n    /// to complete is unacceptable, but you still want the connection to be closed gracefully\n    /// so that the server can clean up resources.\n    #[inline(always)]\n    pub fn close_on_drop(&mut self) {\n        self.close_on_drop = true;\n    }\n\n    /// Detach this connection from the pool, allowing it to open a replacement.\n    ///\n    /// Note that if your application uses a single shared pool, this\n    /// effectively lets the application exceed the [`max_connections`] setting.\n    ///\n    /// If [`min_connections`] is nonzero, a task will be spawned to replace this connection.\n    ///\n    /// If you want the pool to treat this connection as permanently checked-out,\n    /// use [`.leak()`][Self::leak] instead.\n    ///\n    /// [`max_connections`]: crate::pool::PoolOptions::max_connections\n    /// [`min_connections`]: crate::pool::PoolOptions::min_connections\n    pub fn detach(mut self) -> DB::Connection {\n        self.take_live().float(self.pool.clone()).detach()\n    }\n\n    /// Detach this connection from the pool, treating it as permanently checked-out.\n    ///\n    /// This effectively will reduce the maximum capacity of the pool by 1 every time it is used.\n    ///\n    /// If you don't want to impact the pool's capacity, use [`.detach()`][Self::detach] instead.\n    pub fn leak(mut self) -> DB::Connection {\n        self.take_live().raw\n    }\n\n    fn take_live(&mut self) -> Live<DB> {\n        self.live.take().expect(EXPECT_MSG)\n    }\n\n    /// Test the connection to make sure it is still live before returning it to the pool.\n    ///\n    /// This effectively runs the drop handler eagerly instead of spawning a task to do it.\n    #[doc(hidden)]\n    pub fn return_to_pool(&mut self) -> impl Future<Output = ()> + Send + 'static {\n        // float the connection in the pool before we move into the task\n        // in case the returned `Future` isn't executed, like if it's spawned into a dying runtime\n        // https://github.com/launchbadge/sqlx/issues/1396\n        // Type hints seem to be broken by `Option` combinators in IntelliJ Rust right now (6/22).\n        let floating: Option<Floating<DB, Live<DB>>> =\n            self.live.take().map(|live| live.float(self.pool.clone()));\n\n        let pool = self.pool.clone();\n\n        async move {\n            let returned_to_pool = if let Some(floating) = floating {\n                floating.return_to_pool().await\n            } else {\n                false\n            };\n\n            if !returned_to_pool {\n                pool.min_connections_maintenance(None).await;\n            }\n        }\n    }\n\n    fn take_and_close(&mut self) -> impl Future<Output = ()> + Send + 'static {\n        // float the connection in the pool before we move into the task\n        // in case the returned `Future` isn't executed, like if it's spawned into a dying runtime\n        // https://github.com/launchbadge/sqlx/issues/1396\n        // Type hints seem to be broken by `Option` combinators in IntelliJ Rust right now (6/22).\n        let floating = self.live.take().map(|live| live.float(self.pool.clone()));\n\n        let pool = self.pool.clone();\n\n        async move {\n            if let Some(floating) = floating {\n                // Don't hold the connection forever if it hangs while trying to close\n                crate::rt::timeout(CLOSE_ON_DROP_TIMEOUT, floating.close())\n                    .await\n                    .ok();\n            }\n\n            pool.min_connections_maintenance(None).await;\n        }\n    }\n}\n\nimpl<'c, DB: Database> crate::acquire::Acquire<'c> for &'c mut PoolConnection<DB> {\n    type Database = DB;\n\n    type Connection = &'c mut <DB as Database>::Connection;\n\n    #[inline]\n    fn acquire(self) -> futures_core::future::BoxFuture<'c, Result<Self::Connection, Error>> {\n        Box::pin(future::ready(Ok(&mut **self)))\n    }\n\n    #[inline]\n    fn begin(\n        self,\n    ) -> futures_core::future::BoxFuture<'c, Result<crate::transaction::Transaction<'c, DB>, Error>>\n    {\n        crate::transaction::Transaction::begin(&mut **self, None)\n    }\n}\n\n/// Returns the connection to the [`Pool`][crate::pool::Pool] it was checked-out from.\nimpl<DB: Database> Drop for PoolConnection<DB> {\n    fn drop(&mut self) {\n        if self.close_on_drop {\n            crate::rt::spawn(self.take_and_close());\n            return;\n        }\n\n        // We still need to spawn a task to maintain `min_connections`.\n        if self.live.is_some() || self.pool.options.min_connections > 0 {\n            crate::rt::spawn(self.return_to_pool());\n        }\n    }\n}\n\nimpl<DB: Database> Live<DB> {\n    pub fn float(self, pool: Arc<PoolInner<DB>>) -> Floating<DB, Self> {\n        Floating {\n            inner: self,\n            // create a new guard from a previously leaked permit\n            guard: DecrementSizeGuard::new_permit(pool),\n        }\n    }\n\n    pub fn into_idle(self) -> Idle<DB> {\n        Idle {\n            live: self,\n            idle_since: Instant::now(),\n        }\n    }\n}\n\nimpl<DB: Database> Deref for Idle<DB> {\n    type Target = Live<DB>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.live\n    }\n}\n\nimpl<DB: Database> DerefMut for Idle<DB> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.live\n    }\n}\n\nimpl<DB: Database> Floating<DB, Live<DB>> {\n    pub fn new_live(conn: DB::Connection, guard: DecrementSizeGuard<DB>) -> Self {\n        Self {\n            inner: Live {\n                raw: conn,\n                created_at: Instant::now(),\n            },\n            guard,\n        }\n    }\n\n    pub fn reattach(self) -> PoolConnection<DB> {\n        let Floating { inner, guard } = self;\n\n        let pool = Arc::clone(&guard.pool);\n\n        guard.cancel();\n        PoolConnection {\n            live: Some(inner),\n            close_on_drop: false,\n            pool,\n        }\n    }\n\n    pub fn release(self) {\n        self.guard.pool.clone().release(self);\n    }\n\n    /// Return the connection to the pool.\n    ///\n    /// Returns `true` if the connection was successfully returned, `false` if it was closed.\n    async fn return_to_pool(mut self) -> bool {\n        // Immediately close the connection.\n        if self.guard.pool.is_closed() {\n            self.close().await;\n            return false;\n        }\n\n        // If the connection is beyond max lifetime, close the connection and\n        // immediately create a new connection\n        if is_beyond_max_lifetime(&self.inner, &self.guard.pool.options) {\n            self.close().await;\n            return false;\n        }\n\n        if let Some(test) = &self.guard.pool.options.after_release {\n            let meta = self.metadata();\n            match (test)(&mut self.inner.raw, meta).await {\n                Ok(true) => (),\n                Ok(false) => {\n                    self.close().await;\n                    return false;\n                }\n                Err(error) => {\n                    tracing::warn!(%error, \"error from `after_release`\");\n                    // Connection is broken, don't try to gracefully close as\n                    // something weird might happen.\n                    self.close_hard().await;\n                    return false;\n                }\n            }\n        }\n\n        // test the connection on-release to ensure it is still viable,\n        // and flush anything time-sensitive like transaction rollbacks\n        // if an Executor future/stream is dropped during an `.await` call, the connection\n        // is likely to be left in an inconsistent state, in which case it should not be\n        // returned to the pool; also of course, if it was dropped due to an error\n        // this is simply a band-aid as SQLx-next connections should be able\n        // to recover from cancellations\n        if let Err(error) = self.raw.ping().await {\n            tracing::warn!(\n                %error,\n                \"error occurred while testing the connection on-release\",\n            );\n\n            // Connection is broken, don't try to gracefully close.\n            self.close_hard().await;\n            false\n        } else {\n            // if the connection is still viable, release it to the pool\n            self.release();\n            true\n        }\n    }\n\n    pub async fn close(self) {\n        // This isn't used anywhere that we care about the return value\n        let _ = self.inner.raw.close().await;\n\n        // `guard` is dropped as intended\n    }\n\n    pub async fn close_hard(self) {\n        let _ = self.inner.raw.close_hard().await;\n    }\n\n    pub fn detach(self) -> DB::Connection {\n        self.inner.raw\n    }\n\n    pub fn into_idle(self) -> Floating<DB, Idle<DB>> {\n        Floating {\n            inner: self.inner.into_idle(),\n            guard: self.guard,\n        }\n    }\n\n    pub fn metadata(&self) -> PoolConnectionMetadata {\n        PoolConnectionMetadata {\n            age: self.created_at.elapsed(),\n            idle_for: Duration::ZERO,\n        }\n    }\n}\n\nimpl<DB: Database> Floating<DB, Idle<DB>> {\n    pub fn from_idle(\n        idle: Idle<DB>,\n        pool: Arc<PoolInner<DB>>,\n        permit: AsyncSemaphoreReleaser<'_>,\n    ) -> Self {\n        Self {\n            inner: idle,\n            guard: DecrementSizeGuard::from_permit(pool, permit),\n        }\n    }\n\n    pub async fn ping(&mut self) -> Result<(), Error> {\n        self.live.raw.ping().await\n    }\n\n    pub fn into_live(self) -> Floating<DB, Live<DB>> {\n        Floating {\n            inner: self.inner.live,\n            guard: self.guard,\n        }\n    }\n\n    pub async fn close(self) -> DecrementSizeGuard<DB> {\n        if let Err(error) = self.inner.live.raw.close().await {\n            tracing::debug!(%error, \"error occurred while closing the pool connection\");\n        }\n        self.guard\n    }\n\n    pub async fn close_hard(self) -> DecrementSizeGuard<DB> {\n        let _ = self.inner.live.raw.close_hard().await;\n\n        self.guard\n    }\n\n    pub fn metadata(&self) -> PoolConnectionMetadata {\n        // Use a single `now` value for consistency.\n        let now = Instant::now();\n\n        PoolConnectionMetadata {\n            // NOTE: the receiver is the later `Instant` and the arg is the earlier\n            // https://github.com/launchbadge/sqlx/issues/1912\n            age: now.saturating_duration_since(self.created_at),\n            idle_for: now.saturating_duration_since(self.idle_since),\n        }\n    }\n}\n\nimpl<DB: Database, C> Deref for Floating<DB, C> {\n    type Target = C;\n\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl<DB: Database, C> DerefMut for Floating<DB, C> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/pool/executor.rs",
    "content": "use either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::TryStreamExt;\n\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::executor::{Execute, Executor};\nuse crate::pool::Pool;\nuse crate::sql_str::SqlStr;\n\nimpl<'p, DB: Database> Executor<'p> for &'_ Pool<DB>\nwhere\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n{\n    type Database = DB;\n\n    fn fetch_many<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxStream<'e, Result<Either<DB::QueryResult, DB::Row>, Error>>\n    where\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        let pool = self.clone();\n\n        Box::pin(try_stream! {\n            let mut conn = pool.acquire().await?;\n            let mut s = conn.fetch_many(query);\n\n            while let Some(v) = s.try_next().await? {\n                r#yield!(v);\n            }\n\n            Ok(())\n        })\n    }\n\n    fn fetch_optional<'e, 'q: 'e, E>(\n        self,\n        query: E,\n    ) -> BoxFuture<'e, Result<Option<DB::Row>, Error>>\n    where\n        E: 'q + Execute<'q, Self::Database>,\n    {\n        let pool = self.clone();\n\n        Box::pin(async move { pool.acquire().await?.fetch_optional(query).await })\n    }\n\n    fn prepare_with<'e>(\n        self,\n        sql: SqlStr,\n        parameters: &'e [<Self::Database as Database>::TypeInfo],\n    ) -> BoxFuture<'e, Result<<Self::Database as Database>::Statement, Error>>\n    where\n        'p: 'e,\n    {\n        let pool = self.clone();\n\n        Box::pin(async move { pool.acquire().await?.prepare_with(sql, parameters).await })\n    }\n\n    #[doc(hidden)]\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        sql: SqlStr,\n    ) -> BoxFuture<'e, Result<crate::describe::Describe<Self::Database>, Error>> {\n        let pool = self.clone();\n\n        Box::pin(async move { pool.acquire().await?.describe(sql).await })\n    }\n}\n\n// Causes an overflow when evaluating `&mut DB::Connection: Executor`.\n//\n//\n// impl<'c, DB: Database> crate::executor::Executor<'c> for &'c mut crate::pool::PoolConnection<DB>\n// where\n//     &'c mut DB::Connection: Executor<'c, Database = DB>,\n// {\n//     type Database = DB;\n//\n//\n//\n//     #[inline]\n//     fn fetch_many<'e, 'q: 'e, E: 'q>(\n//         self,\n//         query: E,\n//     ) -> futures_core::stream::BoxStream<\n//         'e,\n//         Result<\n//             either::Either<<DB as crate::database::Database>::QueryResult, DB::Row>,\n//             crate::error::Error,\n//         >,\n//     >\n//     where\n//         'c: 'e,\n//         E: crate::executor::Execute<'q, DB>,\n//     {\n//         (**self).fetch_many(query)\n//     }\n//\n//     #[inline]\n//     fn fetch_optional<'e, 'q: 'e, E: 'q>(\n//         self,\n//         query: E,\n//     ) -> futures_core::future::BoxFuture<'e, Result<Option<DB::Row>, crate::error::Error>>\n//     where\n//         'c: 'e,\n//         E: crate::executor::Execute<'q, DB>,\n//     {\n//         (**self).fetch_optional(query)\n//     }\n//\n//     #[inline]\n//     fn prepare_with<'e, 'q: 'e>(\n//         self,\n//         sql: &'q str,\n//         parameters: &'e [<DB as crate::database::Database>::TypeInfo],\n//     ) -> futures_core::future::BoxFuture<\n//         'e,\n//         Result<<DB as crate::database::Database>::Statement<'q>, crate::error::Error>,\n//     >\n//     where\n//         'c: 'e,\n//     {\n//         (**self).prepare_with(sql, parameters)\n//     }\n//\n//     #[doc(hidden)]\n//     #[cfg(feature = \"offline\")]\n//     #[inline]\n//     fn describe<'e, 'q: 'e>(\n//         self,\n//         sql: &'q str,\n//     ) -> futures_core::future::BoxFuture<\n//         'e,\n//         Result<crate::describe::Describe<DB>, crate::error::Error>,\n//     >\n//     where\n//         'c: 'e,\n//     {\n//         (**self).describe(sql)\n//     }\n// }\n"
  },
  {
    "path": "sqlx-core/src/pool/inner.rs",
    "content": "use super::connection::{Floating, Idle, Live};\nuse crate::connection::ConnectOptions;\nuse crate::connection::Connection;\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::pool::{deadline_as_timeout, CloseEvent, Pool, PoolOptions};\nuse crossbeam_queue::ArrayQueue;\n\nuse crate::sync::{AsyncSemaphore, AsyncSemaphoreReleaser};\n\nuse std::cmp;\nuse std::future::{self, Future};\nuse std::pin::pin;\nuse std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};\nuse std::sync::{Arc, RwLock};\nuse std::task::Poll;\n\nuse crate::logger::private_level_filter_to_trace_level;\nuse crate::pool::options::PoolConnectionMetadata;\nuse crate::private_tracing_dynamic_event;\nuse futures_util::FutureExt;\nuse std::time::{Duration, Instant};\nuse tracing::Level;\n\npub(crate) struct PoolInner<DB: Database> {\n    pub(super) connect_options: RwLock<Arc<<DB::Connection as Connection>::Options>>,\n    pub(super) idle_conns: ArrayQueue<Idle<DB>>,\n    pub(super) semaphore: AsyncSemaphore,\n    pub(super) size: AtomicU32,\n    pub(super) num_idle: AtomicUsize,\n    is_closed: AtomicBool,\n    pub(super) on_closed: event_listener::Event,\n    pub(super) options: PoolOptions<DB>,\n    pub(crate) acquire_time_level: Option<Level>,\n    pub(crate) acquire_slow_level: Option<Level>,\n}\n\nimpl<DB: Database> PoolInner<DB> {\n    pub(super) fn new_arc(\n        options: PoolOptions<DB>,\n        connect_options: <DB::Connection as Connection>::Options,\n    ) -> Arc<Self> {\n        let capacity = options.max_connections as usize;\n\n        let semaphore_capacity = if let Some(parent) = &options.parent_pool {\n            assert!(options.max_connections <= parent.options().max_connections);\n            assert_eq!(options.fair, parent.options().fair);\n            // The child pool must steal permits from the parent\n            0\n        } else {\n            capacity\n        };\n\n        let pool = Self {\n            connect_options: RwLock::new(Arc::new(connect_options)),\n            idle_conns: ArrayQueue::new(capacity),\n            semaphore: AsyncSemaphore::new(options.fair, semaphore_capacity),\n            size: AtomicU32::new(0),\n            num_idle: AtomicUsize::new(0),\n            is_closed: AtomicBool::new(false),\n            on_closed: event_listener::Event::new(),\n            acquire_time_level: private_level_filter_to_trace_level(options.acquire_time_level),\n            acquire_slow_level: private_level_filter_to_trace_level(options.acquire_slow_level),\n            options,\n        };\n\n        let pool = Arc::new(pool);\n\n        spawn_maintenance_tasks(&pool);\n\n        pool\n    }\n\n    pub(super) fn size(&self) -> u32 {\n        self.size.load(Ordering::Acquire)\n    }\n\n    pub(super) fn num_idle(&self) -> usize {\n        // We don't use `self.idle_conns.len()` as it waits for the internal\n        // head and tail pointers to stop changing for a moment before calculating the length,\n        // which may take a long time at high levels of churn.\n        //\n        // By maintaining our own atomic count, we avoid that issue entirely.\n        self.num_idle.load(Ordering::Acquire)\n    }\n\n    pub(super) fn is_closed(&self) -> bool {\n        self.is_closed.load(Ordering::Acquire)\n    }\n\n    fn mark_closed(&self) {\n        self.is_closed.store(true, Ordering::Release);\n        self.on_closed.notify(usize::MAX);\n    }\n\n    pub(super) fn close(self: &Arc<Self>) -> impl Future<Output = ()> + '_ {\n        self.mark_closed();\n\n        async move {\n            // For child pools, we need to acquire permits we actually have rather than\n            // max_connections\n            let permits_to_acquire = if self.options.parent_pool.is_some() {\n                // Child pools start with 0 permits, so we acquire based on current size\n                self.size()\n            } else {\n                // Parent pools can acquire all max_connections permits\n                self.options.max_connections\n            };\n\n            let _permits = self.semaphore.acquire(permits_to_acquire).await;\n\n            while let Some(idle) = self.idle_conns.pop() {\n                let _ = idle.live.raw.close().await;\n            }\n\n            self.num_idle.store(0, Ordering::Release);\n            self.size.store(0, Ordering::Release);\n        }\n    }\n\n    pub(crate) fn close_event(&self) -> CloseEvent {\n        CloseEvent {\n            listener: (!self.is_closed()).then(|| self.on_closed.listen()),\n        }\n    }\n\n    /// Attempt to pull a permit from `self.semaphore` or steal one from the parent.\n    ///\n    /// If we steal a permit from the parent but *don't* open a connection,\n    /// it should be returned to the parent.\n    async fn acquire_permit(self: &Arc<Self>) -> Result<AsyncSemaphoreReleaser<'_>, Error> {\n        let parent = self\n            .parent()\n            // If we're already at the max size, we shouldn't try to steal from the parent.\n            // This is just going to cause unnecessary churn in `acquire()`.\n            .filter(|_| self.size() < self.options.max_connections);\n\n        let mut acquire_self = pin!(self.semaphore.acquire(1).fuse());\n        let mut close_event = pin!(self.close_event());\n\n        if let Some(parent) = parent {\n            let mut acquire_parent = pin!(parent.0.semaphore.acquire(1));\n            let mut parent_close_event = pin!(parent.0.close_event());\n\n            let mut poll_parent = false;\n\n            future::poll_fn(|cx| {\n                if close_event.as_mut().poll(cx).is_ready() {\n                    return Poll::Ready(Err(Error::PoolClosed));\n                }\n\n                if parent_close_event.as_mut().poll(cx).is_ready() {\n                    // Propagate the parent's close event to the child.\n                    self.mark_closed();\n                    return Poll::Ready(Err(Error::PoolClosed));\n                }\n\n                if let Poll::Ready(permit) = acquire_self.as_mut().poll(cx) {\n                    return Poll::Ready(Ok(permit));\n                }\n\n                // Don't try the parent right away.\n                if poll_parent {\n                    acquire_parent.as_mut().poll(cx).map(Ok)\n                } else {\n                    poll_parent = true;\n                    cx.waker().wake_by_ref();\n                    Poll::Pending\n                }\n            })\n            .await\n        } else {\n            close_event.do_until(acquire_self).await\n        }\n    }\n\n    fn parent(&self) -> Option<&Pool<DB>> {\n        self.options.parent_pool.as_ref()\n    }\n\n    #[inline]\n    pub(super) fn try_acquire(self: &Arc<Self>) -> Option<Floating<DB, Idle<DB>>> {\n        if self.is_closed() {\n            return None;\n        }\n\n        let permit = self.semaphore.try_acquire(1)?;\n\n        self.pop_idle(permit).ok()\n    }\n\n    fn pop_idle<'a>(\n        self: &'a Arc<Self>,\n        permit: AsyncSemaphoreReleaser<'a>,\n    ) -> Result<Floating<DB, Idle<DB>>, AsyncSemaphoreReleaser<'a>> {\n        if let Some(idle) = self.idle_conns.pop() {\n            self.num_idle.fetch_sub(1, Ordering::AcqRel);\n            Ok(Floating::from_idle(idle, (*self).clone(), permit))\n        } else {\n            Err(permit)\n        }\n    }\n\n    pub(super) fn release(&self, floating: Floating<DB, Live<DB>>) {\n        // `options.after_release` and other checks are in `PoolConnection::return_to_pool()`.\n\n        let Floating { inner: idle, guard } = floating.into_idle();\n\n        if self.idle_conns.push(idle).is_err() {\n            panic!(\"BUG: connection queue overflow in release()\");\n        }\n\n        // NOTE: we need to make sure we drop the permit *after* we push to the idle queue\n        // don't decrease the size\n        guard.release_permit();\n\n        self.num_idle.fetch_add(1, Ordering::AcqRel);\n    }\n\n    /// Try to atomically increment the pool size for a new connection.\n    ///\n    /// Returns `Err` if the pool is at max capacity already or is closed.\n    pub(super) fn try_increment_size<'a>(\n        self: &'a Arc<Self>,\n        permit: AsyncSemaphoreReleaser<'a>,\n    ) -> Result<DecrementSizeGuard<DB>, AsyncSemaphoreReleaser<'a>> {\n        let result = self\n            .size\n            .fetch_update(Ordering::AcqRel, Ordering::Acquire, |size| {\n                if self.is_closed() {\n                    return None;\n                }\n\n                size.checked_add(1)\n                    .filter(|size| size <= &self.options.max_connections)\n            });\n\n        match result {\n            // we successfully incremented the size\n            Ok(_) => Ok(DecrementSizeGuard::from_permit((*self).clone(), permit)),\n            // the pool is at max capacity or is closed\n            Err(_) => Err(permit),\n        }\n    }\n\n    pub(super) async fn acquire(self: &Arc<Self>) -> Result<Floating<DB, Live<DB>>, Error> {\n        if self.is_closed() {\n            return Err(Error::PoolClosed);\n        }\n\n        let acquire_started_at = Instant::now();\n        let deadline = acquire_started_at + self.options.acquire_timeout;\n\n        let acquired = crate::rt::timeout(\n            self.options.acquire_timeout,\n            async {\n                loop {\n                    // Handles the close-event internally\n                    let permit = self.acquire_permit().await?;\n\n\n                    // First attempt to pop a connection from the idle queue.\n                    let guard = match self.pop_idle(permit) {\n\n                        // Then, check that we can use it...\n                        Ok(conn) => match check_idle_conn(conn, &self.options).await {\n\n                            // All good!\n                            Ok(live) => return Ok(live),\n\n                            // if the connection isn't usable for one reason or another,\n                            // we get the `DecrementSizeGuard` back to open a new one\n                            Err(guard) => guard,\n                        },\n                        Err(permit) => if let Ok(guard) = self.try_increment_size(permit) {\n                            // we can open a new connection\n                            guard\n                        } else {\n                            // This can happen for a child pool that's at its connection limit,\n                            // or if the pool was closed between `acquire_permit()` and\n                            // `try_increment_size()`.\n                            tracing::debug!(\"woke but was unable to acquire idle connection or open new one; retrying\");\n                            // If so, we're likely in the current-thread runtime if it's Tokio,\n                            // and so we should yield to let any spawned return_to_pool() tasks\n                            // execute.\n                            crate::rt::yield_now().await;\n                            continue;\n                        }\n                    };\n\n                    // Attempt to connect...\n                    return self.connect(deadline, guard).await;\n                }\n            }\n        )\n            .await\n            .map_err(|_| Error::PoolTimedOut)??;\n\n        let acquired_after = acquire_started_at.elapsed();\n\n        let acquire_slow_level = self\n            .acquire_slow_level\n            .filter(|_| acquired_after > self.options.acquire_slow_threshold);\n\n        if let Some(level) = acquire_slow_level {\n            private_tracing_dynamic_event!(\n                target: \"sqlx::pool::acquire\",\n                level,\n                acquired_after_secs = acquired_after.as_secs_f64(),\n                slow_acquire_threshold_secs = self.options.acquire_slow_threshold.as_secs_f64(),\n                \"acquired connection, but time to acquire exceeded slow threshold\"\n            );\n        } else if let Some(level) = self.acquire_time_level {\n            private_tracing_dynamic_event!(\n                target: \"sqlx::pool::acquire\",\n                level,\n                acquired_after_secs = acquired_after.as_secs_f64(),\n                \"acquired connection\"\n            );\n        }\n\n        Ok(acquired)\n    }\n\n    pub(super) async fn connect(\n        self: &Arc<Self>,\n        deadline: Instant,\n        guard: DecrementSizeGuard<DB>,\n    ) -> Result<Floating<DB, Live<DB>>, Error> {\n        if self.is_closed() {\n            return Err(Error::PoolClosed);\n        }\n\n        let mut backoff = Duration::from_millis(10);\n        let max_backoff = deadline_as_timeout(deadline)? / 5;\n\n        loop {\n            let timeout = deadline_as_timeout(deadline)?;\n\n            // clone the connect options arc so it can be used without holding the RwLockReadGuard\n            // across an async await point\n            let connect_options = self\n                .connect_options\n                .read()\n                .expect(\"write-lock holder panicked\")\n                .clone();\n\n            // result here is `Result<Result<C, Error>, TimeoutError>`\n            // if this block does not return, sleep for the backoff timeout and try again\n            match crate::rt::timeout(timeout, connect_options.connect()).await {\n                // successfully established connection\n                Ok(Ok(mut raw)) => {\n                    // See comment on `PoolOptions::after_connect`\n                    let meta = PoolConnectionMetadata {\n                        age: Duration::ZERO,\n                        idle_for: Duration::ZERO,\n                    };\n\n                    let res = if let Some(callback) = &self.options.after_connect {\n                        callback(&mut raw, meta).await\n                    } else {\n                        Ok(())\n                    };\n\n                    match res {\n                        Ok(()) => return Ok(Floating::new_live(raw, guard)),\n                        Err(error) => {\n                            tracing::error!(%error, \"error returned from after_connect\");\n                            // The connection is broken, don't try to close nicely.\n                            let _ = raw.close_hard().await;\n\n                            // Fall through to the backoff.\n                        }\n                    }\n                }\n\n                // an IO error while connecting is assumed to be the system starting up\n                Ok(Err(Error::Io(e))) if e.kind() == std::io::ErrorKind::ConnectionRefused => (),\n\n                // We got a transient database error, retry.\n                Ok(Err(Error::Database(error))) if error.is_transient_in_connect_phase() => (),\n\n                // Any other error while connection should immediately\n                // terminate and bubble the error up\n                Ok(Err(e)) => return Err(e),\n\n                // timed out\n                Err(_) => return Err(Error::PoolTimedOut),\n            }\n\n            // If the connection is refused, wait in exponentially\n            // increasing steps for the server to come up,\n            // capped by a factor of the remaining time until the deadline\n            crate::rt::sleep(backoff).await;\n            backoff = cmp::min(backoff * 2, max_backoff);\n        }\n    }\n\n    /// Try to maintain `min_connections`, returning any errors (including `PoolTimedOut`).\n    pub async fn try_min_connections(self: &Arc<Self>, deadline: Instant) -> Result<(), Error> {\n        while self.size() < self.options.min_connections {\n            // Don't wait for a semaphore permit.\n            //\n            // If no extra permits are available then we shouldn't be trying to spin up\n            // connections anyway.\n            let Some(permit) = self.semaphore.try_acquire(1) else {\n                return Ok(());\n            };\n\n            // We must always obey `max_connections`.\n            let Some(guard) = self.try_increment_size(permit).ok() else {\n                return Ok(());\n            };\n\n            // We skip `after_release` since the connection was never provided to user code\n            // besides `after_connect`, if they set it.\n            self.release(self.connect(deadline, guard).await?);\n        }\n\n        Ok(())\n    }\n\n    /// Attempt to maintain `min_connections`, logging if unable.\n    pub async fn min_connections_maintenance(self: &Arc<Self>, deadline: Option<Instant>) {\n        let deadline = deadline.unwrap_or_else(|| {\n            // Arbitrary default deadline if the caller doesn't care.\n            Instant::now() + Duration::from_secs(300)\n        });\n\n        match self.try_min_connections(deadline).await {\n            Ok(()) => (),\n            Err(Error::PoolClosed) => (),\n            Err(Error::PoolTimedOut) => {\n                tracing::debug!(\"unable to complete `min_connections` maintenance before deadline\")\n            }\n            Err(error) => tracing::debug!(%error, \"error while maintaining min_connections\"),\n        }\n    }\n}\n\nimpl<DB: Database> Drop for PoolInner<DB> {\n    fn drop(&mut self) {\n        self.mark_closed();\n\n        if let Some(parent) = &self.options.parent_pool {\n            // Release the stolen permits.\n            parent.0.semaphore.release(self.semaphore.permits());\n        }\n    }\n}\n\n/// Returns `true` if the connection has exceeded `options.max_lifetime` if set, `false` otherwise.\npub(super) fn is_beyond_max_lifetime<DB: Database>(\n    live: &Live<DB>,\n    options: &PoolOptions<DB>,\n) -> bool {\n    options\n        .max_lifetime\n        .is_some_and(|max| live.created_at.elapsed() > max)\n}\n\n/// Returns `true` if the connection has exceeded `options.idle_timeout` if set, `false` otherwise.\nfn is_beyond_idle_timeout<DB: Database>(idle: &Idle<DB>, options: &PoolOptions<DB>) -> bool {\n    options\n        .idle_timeout\n        .is_some_and(|timeout| idle.idle_since.elapsed() > timeout)\n}\n\nasync fn check_idle_conn<DB: Database>(\n    mut conn: Floating<DB, Idle<DB>>,\n    options: &PoolOptions<DB>,\n) -> Result<Floating<DB, Live<DB>>, DecrementSizeGuard<DB>> {\n    if options.test_before_acquire {\n        // Check that the connection is still live\n        if let Err(error) = conn.ping().await {\n            // an error here means the other end has hung up or we lost connectivity\n            // either way we're fine to just discard the connection\n            // the error itself here isn't necessarily unexpected so WARN is too strong\n            tracing::info!(%error, \"ping on idle connection returned error\");\n            // connection is broken so don't try to close nicely\n            return Err(conn.close_hard().await);\n        }\n    }\n\n    if let Some(test) = &options.before_acquire {\n        let meta = conn.metadata();\n        match test(&mut conn.live.raw, meta).await {\n            Ok(false) => {\n                // connection was rejected by user-defined hook, close nicely\n                return Err(conn.close().await);\n            }\n\n            Err(error) => {\n                tracing::warn!(%error, \"error from `before_acquire`\");\n                // connection is broken so don't try to close nicely\n                return Err(conn.close_hard().await);\n            }\n\n            Ok(true) => {}\n        }\n    }\n\n    // No need to re-connect; connection is alive or we don't care\n    Ok(conn.into_live())\n}\n\nfn spawn_maintenance_tasks<DB: Database>(pool: &Arc<PoolInner<DB>>) {\n    // NOTE: use `pool_weak` for the maintenance tasks\n    // so they don't keep `PoolInner` from being dropped.\n    let pool_weak = Arc::downgrade(pool);\n\n    let period = match (pool.options.max_lifetime, pool.options.idle_timeout) {\n        (Some(it), None) | (None, Some(it)) => it,\n\n        (Some(a), Some(b)) => cmp::min(a, b),\n\n        (None, None) => {\n            if pool.options.min_connections > 0 {\n                crate::rt::spawn(async move {\n                    if let Some(pool) = pool_weak.upgrade() {\n                        pool.min_connections_maintenance(None).await;\n                    }\n                });\n            }\n\n            return;\n        }\n    };\n\n    // Immediately cancel this task if the pool is closed.\n    let mut close_event = pool.close_event();\n\n    crate::rt::spawn(async move {\n        let _ = close_event\n            .do_until(async {\n                // If the last handle to the pool was dropped while we were sleeping\n                while let Some(pool) = pool_weak.upgrade() {\n                    if pool.is_closed() {\n                        return;\n                    }\n\n                    let next_run = Instant::now() + period;\n\n                    // Go over all idle connections, check for idleness and lifetime,\n                    // and if we have fewer than min_connections after reaping a connection,\n                    // open a new one immediately. Note that other connections may be popped from\n                    // the queue in the meantime - that's fine, there is no harm in checking more\n                    for _ in 0..pool.num_idle() {\n                        if let Some(conn) = pool.try_acquire() {\n                            if is_beyond_idle_timeout(&conn, &pool.options)\n                                || is_beyond_max_lifetime(&conn, &pool.options)\n                            {\n                                let _ = conn.close().await;\n                                pool.min_connections_maintenance(Some(next_run)).await;\n                            } else {\n                                pool.release(conn.into_live());\n                            }\n                        }\n                    }\n\n                    // Don't hold a reference to the pool while sleeping.\n                    drop(pool);\n\n                    if let Some(duration) = next_run.checked_duration_since(Instant::now()) {\n                        // `async-std` doesn't have a `sleep_until()`\n                        crate::rt::sleep(duration).await;\n                    } else {\n                        // `next_run` is in the past, just yield.\n                        crate::rt::yield_now().await;\n                    }\n                }\n            })\n            .await;\n    });\n}\n\n/// RAII guard returned by `Pool::try_increment_size()` and others.\n///\n/// Will decrement the pool size if dropped, to avoid semantically \"leaking\" connections\n/// (where the pool thinks it has more connections than it does).\npub(in crate::pool) struct DecrementSizeGuard<DB: Database> {\n    pub(crate) pool: Arc<PoolInner<DB>>,\n    cancelled: bool,\n}\n\nimpl<DB: Database> DecrementSizeGuard<DB> {\n    /// Create a new guard that will release a semaphore permit on-drop.\n    pub fn new_permit(pool: Arc<PoolInner<DB>>) -> Self {\n        Self {\n            pool,\n            cancelled: false,\n        }\n    }\n\n    pub fn from_permit(pool: Arc<PoolInner<DB>>, permit: AsyncSemaphoreReleaser<'_>) -> Self {\n        // here we effectively take ownership of the permit\n        permit.disarm();\n        Self::new_permit(pool)\n    }\n\n    /// Release the semaphore permit without decreasing the pool size.\n    ///\n    /// If the permit was stolen from the pool's parent, it will be returned to the child's semaphore.\n    fn release_permit(self) {\n        self.pool.semaphore.release(1);\n        self.cancel();\n    }\n\n    pub fn cancel(mut self) {\n        self.cancelled = true;\n    }\n}\n\nimpl<DB: Database> Drop for DecrementSizeGuard<DB> {\n    fn drop(&mut self) {\n        if !self.cancelled {\n            self.pool.size.fetch_sub(1, Ordering::AcqRel);\n\n            // and here we release the permit we got on construction\n            self.pool.semaphore.release(1);\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/pool/maybe.rs",
    "content": "use crate::database::Database;\nuse crate::pool::PoolConnection;\nuse std::ops::{Deref, DerefMut};\n\npub enum MaybePoolConnection<'c, DB: Database> {\n    #[allow(dead_code)]\n    Connection(&'c mut DB::Connection),\n    PoolConnection(PoolConnection<DB>),\n}\n\nimpl<DB: Database> Deref for MaybePoolConnection<'_, DB> {\n    type Target = DB::Connection;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        match self {\n            MaybePoolConnection::Connection(v) => v,\n            MaybePoolConnection::PoolConnection(v) => v,\n        }\n    }\n}\n\nimpl<DB: Database> DerefMut for MaybePoolConnection<'_, DB> {\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        match self {\n            MaybePoolConnection::Connection(v) => v,\n            MaybePoolConnection::PoolConnection(v) => v,\n        }\n    }\n}\n\nimpl<DB: Database> From<PoolConnection<DB>> for MaybePoolConnection<'_, DB> {\n    fn from(v: PoolConnection<DB>) -> Self {\n        MaybePoolConnection::PoolConnection(v)\n    }\n}\n\nimpl<'c, DB: Database> From<&'c mut DB::Connection> for MaybePoolConnection<'c, DB> {\n    fn from(v: &'c mut DB::Connection) -> Self {\n        MaybePoolConnection::Connection(v)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/pool/mod.rs",
    "content": "//! Provides the connection pool for asynchronous SQLx connections.\n//!\n//! Opening a database connection for each and every operation to the database can quickly\n//! become expensive. Furthermore, sharing a database connection between threads and functions\n//! can be difficult to express in Rust.\n//!\n//! A connection pool is a standard technique that can manage opening and re-using connections.\n//! Normally it also enforces a maximum number of connections as these are an expensive resource\n//! on the database server.\n//!\n//! SQLx provides a canonical connection pool implementation intended to satisfy the majority\n//! of use cases.\n//!\n//! See [Pool] for details.\n//!\n//! Type aliases are provided for each database to make it easier to sprinkle `Pool` through\n//! your codebase:\n//!\n//! * [MssqlPool][crate::mssql::MssqlPool] (MSSQL)\n//! * [MySqlPool][crate::mysql::MySqlPool] (MySQL)\n//! * [PgPool][crate::postgres::PgPool] (PostgreSQL)\n//! * [SqlitePool][crate::sqlite::SqlitePool] (SQLite)\n//!\n//! # Opening a connection pool\n//!\n//! A new connection pool with a default configuration can be created by supplying `Pool`\n//! with the database driver and a connection string.\n//!\n//! ```rust,ignore\n//! use sqlx::Pool;\n//! use sqlx::postgres::Postgres;\n//!\n//! let pool = Pool::<Postgres>::connect(\"postgres://\").await?;\n//! ```\n//!\n//! For convenience, database-specific type aliases are provided:\n//!\n//! ```rust,ignore\n//! use sqlx::mssql::MssqlPool;\n//!\n//! let pool = MssqlPool::connect(\"mssql://\").await?;\n//! ```\n//!\n//! # Using a connection pool\n//!\n//! A connection pool implements [`Executor`][crate::executor::Executor] and can be used directly\n//! when executing a query. Notice that only an immutable reference (`&Pool`) is needed.\n//!\n//! ```rust,ignore\n//! sqlx::query(\"DELETE FROM articles\").execute(&pool).await?;\n//! ```\n//!\n//! A connection or transaction may also be manually acquired with\n//! [`Pool::acquire`] or\n//! [`Pool::begin`].\n\nuse std::fmt;\nuse std::future::Future;\nuse std::pin::{pin, Pin};\nuse std::sync::Arc;\nuse std::task::{ready, Context, Poll};\nuse std::time::{Duration, Instant};\n\nuse event_listener::EventListener;\nuse futures_core::FusedFuture;\nuse futures_util::FutureExt;\n\nuse crate::connection::Connection;\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::sql_str::SqlSafeStr;\nuse crate::transaction::Transaction;\n\npub use self::connection::PoolConnection;\nuse self::inner::PoolInner;\n#[doc(hidden)]\npub use self::maybe::MaybePoolConnection;\npub use self::options::{PoolConnectionMetadata, PoolOptions};\n\n#[macro_use]\nmod executor;\n\n#[macro_use]\npub mod maybe;\n\nmod connection;\nmod inner;\nmod options;\n\n/// An asynchronous pool of SQLx database connections.\n///\n/// Create a pool with [Pool::connect] or [Pool::connect_with] and then call [Pool::acquire]\n/// to get a connection from the pool; when the connection is dropped it will return to the pool\n/// so it can be reused.\n///\n/// You can also pass `&Pool` directly anywhere an `Executor` is required; this will automatically\n/// checkout a connection for you.\n///\n/// See [the module documentation](crate::pool) for examples.\n///\n/// The pool has a maximum connection limit that it will not exceed; if `acquire()` is called\n/// when at this limit and all connections are checked out, the task will be made to wait until\n/// a connection becomes available.\n///\n/// You can configure the connection limit, and other parameters, using [PoolOptions].\n///\n/// Calls to `acquire()` are fair, i.e. fulfilled on a first-come, first-serve basis.\n///\n/// `Pool` is `Send`, `Sync` and `Clone`. It is intended to be created once at the start of your\n/// application/daemon/web server/etc. and then shared with all tasks throughout the process'\n/// lifetime. How best to accomplish this depends on your program architecture.\n///\n/// In Actix-Web, for example, you can efficiently share a single pool with all request handlers\n/// using [web::ThinData].\n///\n/// Cloning `Pool` is cheap as it is simply a reference-counted handle to the inner pool state.\n/// When the last remaining handle to the pool is dropped, the connections owned by the pool are\n/// immediately closed (also by dropping). `PoolConnection` returned by [Pool::acquire] and\n/// `Transaction` returned by [Pool::begin] both implicitly hold a reference to the pool for\n/// their lifetimes.\n///\n/// If you prefer to explicitly shutdown the pool and gracefully close its connections (which\n/// depending on the database type, may include sending a message to the database server that the\n/// connection is being closed), you can call [Pool::close] which causes all waiting and subsequent\n/// calls to [Pool::acquire] to return [Error::PoolClosed], and waits until all connections have\n/// been returned to the pool and gracefully closed.\n///\n/// Type aliases are provided for each database to make it easier to sprinkle `Pool` through\n/// your codebase:\n///\n/// * [MssqlPool][crate::mssql::MssqlPool] (MSSQL)\n/// * [MySqlPool][crate::mysql::MySqlPool] (MySQL)\n/// * [PgPool][crate::postgres::PgPool] (PostgreSQL)\n/// * [SqlitePool][crate::sqlite::SqlitePool] (SQLite)\n///\n/// [web::ThinData]: https://docs.rs/actix-web/4.9.0/actix_web/web/struct.ThinData.html\n///\n/// ### Note: Drop Behavior\n/// Due to a lack of async `Drop`, dropping the last `Pool` handle may not immediately clean\n/// up connections by itself. The connections will be dropped locally, which is sufficient for\n/// SQLite, but for client/server databases like MySQL and Postgres, that only closes the\n/// client side of the connection. The server will not know the connection is closed until\n/// potentially much later: this is usually dictated by the TCP keepalive timeout in the server\n/// settings.\n///\n/// Because the connection may not be cleaned up immediately on the server side, you may run\n/// into errors regarding connection limits if you are creating and dropping many pools in short\n/// order.\n///\n/// We recommend calling [`.close().await`] to gracefully close the pool and its connections\n/// when you are done using it. This will also wake any tasks that are waiting on an `.acquire()`\n/// call, so for long-lived applications it's a good idea to call `.close()` during shutdown.\n///\n/// If you're writing tests, consider using `#[sqlx::test]` which handles the lifetime of\n/// the pool for you.\n///\n/// [`.close().await`]: Pool::close\n///\n/// ### Why Use a Pool?\n///\n/// A single database connection (in general) cannot be used by multiple threads simultaneously\n/// for various reasons, but an application or web server will typically need to execute numerous\n/// queries or commands concurrently (think of concurrent requests against a web server; many or all\n/// of them will probably need to hit the database).\n///\n/// You could place the connection in a `Mutex` but this will make it a huge bottleneck.\n///\n/// Naively, you might also think to just open a new connection per request, but this\n/// has a number of other caveats, generally due to the high overhead involved in working with\n/// a fresh connection. Examples to follow.\n///\n/// Connection pools facilitate reuse of connections to _amortize_ these costs, helping to ensure\n/// that you're not paying for them each time you need a connection.\n///\n/// ##### 1. Overhead of Opening a Connection\n/// Opening a database connection is not exactly a cheap operation.\n///\n/// For SQLite, it means numerous requests to the filesystem and memory allocations, while for\n/// server-based databases it involves performing DNS resolution, opening a new TCP connection and\n/// allocating buffers.\n///\n/// Each connection involves a nontrivial allocation of resources for the database server, usually\n/// including spawning a new thread or process specifically to handle the connection, both for\n/// concurrency and isolation of faults.\n///\n/// Additionally, database connections typically involve a complex handshake including\n/// authentication, negotiation regarding connection parameters (default character sets, timezones,\n/// locales, supported features) and upgrades to encrypted tunnels.\n///\n/// If `acquire()` is called on a pool with all connections checked out but it is not yet at its\n/// connection limit (see next section), then a new connection is immediately opened, so this pool\n/// does not _automatically_ save you from the overhead of creating a new connection.\n///\n/// However, because this pool by design enforces _reuse_ of connections, this overhead cost\n/// is not paid each and every time you need a connection. In fact, if you set\n/// [the `min_connections` option in PoolOptions][PoolOptions::min_connections], the pool will\n/// create that many connections up-front so that they are ready to go when a request comes in,\n/// and maintain that number on a best-effort basis for consistent performance.\n///\n/// ##### 2. Connection Limits (MySQL, MSSQL, Postgres)\n/// Database servers usually place hard limits on the number of connections that are allowed open at\n/// any given time, to maintain performance targets and prevent excessive allocation of resources,\n/// such as RAM, journal files, disk caches, etc.\n///\n/// These limits have different defaults per database flavor, and may vary between different\n/// distributions of the same database, but are typically configurable on server start;\n/// if you're paying for managed database hosting then the connection limit will typically vary with\n/// your pricing tier.\n///\n/// In MySQL, the default limit is typically 150, plus 1 which is reserved for a user with the\n/// `CONNECTION_ADMIN` privilege so you can still access the server to diagnose problems even\n/// with all connections being used.\n///\n/// In MSSQL the only documentation for the default maximum limit is that it depends on the version\n/// and server configuration.\n///\n/// In Postgres, the default limit is typically 100, minus 3 which are reserved for superusers\n/// (putting the default limit for unprivileged users at 97 connections).\n///\n/// In any case, exceeding these limits results in an error when opening a new connection, which\n/// in a web server context will turn into a `500 Internal Server Error` if not handled, but should\n/// be turned into either `403 Forbidden` or `429 Too Many Requests` depending on your rate-limiting\n/// scheme. However, in a web context, telling a client \"go away, maybe try again later\" results in\n/// a sub-optimal user experience.\n///\n/// Instead, with a connection pool, clients are made to wait in a fair queue for a connection to\n/// become available; by using a single connection pool for your whole application, you can ensure\n/// that you don't exceed the connection limit of your database server while allowing response\n/// time to degrade gracefully at high load.\n///\n/// Of course, if multiple applications are connecting to the same database server, then you\n/// should ensure that the connection limits for all applications add up to your server's maximum\n/// connections or less.\n///\n/// ##### 3. Resource Reuse\n/// The first time you execute a query against your database, the database engine must first turn\n/// the SQL into an actionable _query plan_ which it may then execute against the database. This\n/// involves parsing the SQL query, validating and analyzing it, and in the case of Postgres 12+ and\n/// SQLite, generating code to execute the query plan (native or bytecode, respectively).\n///\n/// These database servers provide a way to amortize this overhead by _preparing_ the query,\n/// associating it with an object ID and placing its query plan in a cache to be referenced when\n/// it is later executed.\n///\n/// Prepared statements have other features, like bind parameters, which make them safer and more\n/// ergonomic to use as well. By design, SQLx pushes you towards using prepared queries/statements\n/// via the [Query][crate::query::Query] API _et al._ and the `query!()` macro _et al._, for\n/// reasons of safety, ergonomics, and efficiency.\n///\n/// However, because database connections are typically isolated from each other in the database\n/// server (either by threads or separate processes entirely), they don't typically share prepared\n/// statements between connections so this work must be redone _for each connection_.\n///\n/// As with section 1, by facilitating reuse of connections, `Pool` helps to ensure their prepared\n/// statements (and thus cached query plans) can be reused as much as possible, thus amortizing\n/// the overhead involved.\n///\n/// Depending on the database server, a connection will have caches for all kinds of other data as\n/// well and queries will generally benefit from these caches being \"warm\" (populated with data).\npub struct Pool<DB: Database>(pub(crate) Arc<PoolInner<DB>>);\n\n/// A future that resolves when the pool is closed.\n///\n/// See [`Pool::close_event()`] for details.\npub struct CloseEvent {\n    listener: Option<EventListener>,\n}\n\nimpl<DB: Database> Pool<DB> {\n    /// Create a new connection pool with a default pool configuration and\n    /// the given connection URL, and immediately establish one connection.\n    ///\n    /// Refer to the relevant `ConnectOptions` impl for your database for the expected URL format:\n    ///\n    /// * Postgres: [`PgConnectOptions`][crate::postgres::PgConnectOptions]\n    /// * MySQL: [`MySqlConnectOptions`][crate::mysql::MySqlConnectOptions]\n    /// * SQLite: [`SqliteConnectOptions`][crate::sqlite::SqliteConnectOptions]\n    /// * MSSQL: [`MssqlConnectOptions`][crate::mssql::MssqlConnectOptions]\n    ///\n    /// The default configuration is mainly suited for testing and light-duty applications.\n    /// For production applications, you'll likely want to make at least few tweaks.\n    ///\n    /// See [`PoolOptions::new()`] for details.\n    pub async fn connect(url: &str) -> Result<Self, Error> {\n        PoolOptions::<DB>::new().connect(url).await\n    }\n\n    /// Create a new connection pool with a default pool configuration and\n    /// the given `ConnectOptions`, and immediately establish one connection.\n    ///\n    /// The default configuration is mainly suited for testing and light-duty applications.\n    /// For production applications, you'll likely want to make at least few tweaks.\n    ///\n    /// See [`PoolOptions::new()`] for details.\n    pub async fn connect_with(\n        options: <DB::Connection as Connection>::Options,\n    ) -> Result<Self, Error> {\n        PoolOptions::<DB>::new().connect_with(options).await\n    }\n\n    /// Create a new connection pool with a default pool configuration and\n    /// the given connection URL.\n    ///\n    /// The pool will establish connections only as needed.\n    ///\n    /// Refer to the relevant [`ConnectOptions`][crate::connection::ConnectOptions] impl for your database for the expected URL format:\n    ///\n    /// * Postgres: [`PgConnectOptions`][crate::postgres::PgConnectOptions]\n    /// * MySQL: [`MySqlConnectOptions`][crate::mysql::MySqlConnectOptions]\n    /// * SQLite: [`SqliteConnectOptions`][crate::sqlite::SqliteConnectOptions]\n    /// * MSSQL: [`MssqlConnectOptions`][crate::mssql::MssqlConnectOptions]\n    ///\n    /// The default configuration is mainly suited for testing and light-duty applications.\n    /// For production applications, you'll likely want to make at least few tweaks.\n    ///\n    /// See [`PoolOptions::new()`] for details.\n    pub fn connect_lazy(url: &str) -> Result<Self, Error> {\n        PoolOptions::<DB>::new().connect_lazy(url)\n    }\n\n    /// Create a new connection pool with a default pool configuration and\n    /// the given `ConnectOptions`.\n    ///\n    /// The pool will establish connections only as needed.\n    ///\n    /// The default configuration is mainly suited for testing and light-duty applications.\n    /// For production applications, you'll likely want to make at least few tweaks.\n    ///\n    /// See [`PoolOptions::new()`] for details.\n    pub fn connect_lazy_with(options: <DB::Connection as Connection>::Options) -> Self {\n        PoolOptions::<DB>::new().connect_lazy_with(options)\n    }\n\n    /// Retrieves a connection from the pool.\n    ///\n    /// The total time this method is allowed to execute is capped by\n    /// [`PoolOptions::acquire_timeout`].\n    /// If that timeout elapses, this will return [`Error::PoolClosed`].\n    ///\n    /// ### Note: Cancellation/Timeout May Drop Connections\n    /// If `acquire` is cancelled or times out after it acquires a connection from the idle queue or\n    /// opens a new one, it will drop that connection because we don't want to assume it\n    /// is safe to return to the pool, and testing it to see if it's safe to release could introduce\n    /// subtle bugs if not implemented correctly. To avoid that entirely, we've decided to not\n    /// gracefully handle cancellation here.\n    ///\n    /// However, if your workload is sensitive to dropped connections such as using an in-memory\n    /// SQLite database with a pool size of 1, you can pretty easily ensure that a cancelled\n    /// `acquire()` call will never drop connections by tweaking your [`PoolOptions`]:\n    ///\n    /// * Set [`test_before_acquire(false)`][PoolOptions::test_before_acquire]\n    /// * Never set [`before_acquire`][PoolOptions::before_acquire] or\n    ///   [`after_connect`][PoolOptions::after_connect].\n    ///\n    /// This should eliminate any potential `.await` points between acquiring a connection and\n    /// returning it.\n    pub fn acquire(&self) -> impl Future<Output = Result<PoolConnection<DB>, Error>> + 'static {\n        let shared = self.0.clone();\n        async move { shared.acquire().await.map(|conn| conn.reattach()) }\n    }\n\n    /// Attempts to retrieve a connection from the pool if there is one available.\n    ///\n    /// Returns `None` immediately if there are no idle connections available in the pool\n    /// or there are tasks waiting for a connection which have yet to wake.\n    pub fn try_acquire(&self) -> Option<PoolConnection<DB>> {\n        self.0.try_acquire().map(|conn| conn.into_live().reattach())\n    }\n\n    /// Retrieves a connection and immediately begins a new transaction.\n    pub async fn begin(&self) -> Result<Transaction<'static, DB>, Error> {\n        Transaction::begin(\n            MaybePoolConnection::PoolConnection(self.acquire().await?),\n            None,\n        )\n        .await\n    }\n\n    /// Attempts to retrieve a connection and immediately begins a new transaction if successful.\n    pub async fn try_begin(&self) -> Result<Option<Transaction<'static, DB>>, Error> {\n        match self.try_acquire() {\n            Some(conn) => Transaction::begin(MaybePoolConnection::PoolConnection(conn), None)\n                .await\n                .map(Some),\n\n            None => Ok(None),\n        }\n    }\n\n    /// Retrieves a connection and immediately begins a new transaction using `statement`.\n    pub async fn begin_with(\n        &self,\n        statement: impl SqlSafeStr,\n    ) -> Result<Transaction<'static, DB>, Error> {\n        Transaction::begin(\n            MaybePoolConnection::PoolConnection(self.acquire().await?),\n            Some(statement.into_sql_str()),\n        )\n        .await\n    }\n\n    /// Attempts to retrieve a connection and, if successful, immediately begins a new\n    /// transaction using `statement`.\n    pub async fn try_begin_with(\n        &self,\n        statement: impl SqlSafeStr,\n    ) -> Result<Option<Transaction<'static, DB>>, Error> {\n        match self.try_acquire() {\n            Some(conn) => Transaction::begin(\n                MaybePoolConnection::PoolConnection(conn),\n                Some(statement.into_sql_str()),\n            )\n            .await\n            .map(Some),\n\n            None => Ok(None),\n        }\n    }\n\n    /// Shut down the connection pool, immediately waking all tasks waiting for a connection.\n    ///\n    /// Upon calling this method, any currently waiting or subsequent calls to [`Pool::acquire`] and\n    /// the like will immediately return [`Error::PoolClosed`] and no new connections will be opened.\n    /// Checked-out connections are unaffected, but will be gracefully closed on-drop\n    /// rather than being returned to the pool.\n    ///\n    /// Returns a `Future` which can be `.await`ed to ensure all connections are\n    /// gracefully closed. It will first close any idle connections currently waiting in the pool,\n    /// then wait for all checked-out connections to be returned or closed.\n    ///\n    /// Waiting for connections to be gracefully closed is optional, but will allow the database\n    /// server to clean up the resources sooner rather than later. This is especially important\n    /// for tests that create a new pool every time, otherwise you may see errors about connection\n    /// limits being exhausted even when running tests in a single thread.\n    ///\n    /// If the returned `Future` is not run to completion, any remaining connections will be dropped\n    /// when the last handle for the given pool instance is dropped, which could happen in a task\n    /// spawned by `Pool` internally and so may be unpredictable otherwise.\n    ///\n    /// `.close()` may be safely called and `.await`ed on multiple handles concurrently.\n    pub fn close(&self) -> impl Future<Output = ()> + '_ {\n        self.0.close()\n    }\n\n    /// Returns `true` if [`.close()`][Pool::close] has been called on the pool, `false` otherwise.\n    pub fn is_closed(&self) -> bool {\n        self.0.is_closed()\n    }\n\n    /// Get a future that resolves when [`Pool::close()`] is called.\n    ///\n    /// If the pool is already closed, the future resolves immediately.\n    ///\n    /// This can be used to cancel long-running operations that hold onto a [`PoolConnection`]\n    /// so they don't prevent the pool from closing (which would otherwise wait until all\n    /// connections are returned).\n    ///\n    /// Examples\n    /// ========\n    /// These examples use Postgres and Tokio, but should suffice to demonstrate the concept.\n    ///\n    /// Do something when the pool is closed:\n    /// ```rust,no_run\n    /// # async fn bleh() -> sqlx::Result<()> {\n    /// use sqlx::PgPool;\n    ///\n    /// let pool = PgPool::connect(\"postgresql://...\").await?;\n    ///\n    /// let pool2 = pool.clone();\n    ///\n    /// tokio::spawn(async move {\n    ///     // Demonstrates that `CloseEvent` is itself a `Future` you can wait on.\n    ///     // This lets you implement any kind of on-close event that you like.\n    ///     pool2.close_event().await;\n    ///\n    ///     println!(\"Pool is closing!\");\n    ///\n    ///     // Imagine maybe recording application statistics or logging a report, etc.\n    /// });\n    ///\n    /// // The rest of the application executes normally...\n    ///\n    /// // Close the pool before the application exits...\n    /// pool.close().await;\n    ///\n    /// # Ok(())\n    /// # }\n    /// ```\n    ///\n    /// Cancel a long-running operation:\n    /// ```rust,no_run\n    /// # async fn bleh() -> sqlx::Result<()> {\n    /// use sqlx::{Executor, PgPool};\n    ///\n    /// let pool = PgPool::connect(\"postgresql://...\").await?;\n    ///\n    /// let pool2 = pool.clone();\n    ///\n    /// tokio::spawn(async move {\n    ///     // `do_until` yields the inner future's output wrapped in `sqlx::Result`,\n    ///     // in this case giving a double-wrapped result.\n    ///     let res: sqlx::Result<sqlx::Result<()>> = pool2.close_event().do_until(async {\n    ///         // This statement normally won't return for 30 days!\n    ///         // (Assuming the connection doesn't time out first, of course.)\n    ///         pool2.execute(\"SELECT pg_sleep('30 days')\").await?;\n    ///\n    ///         // If the pool is closed before the statement completes, this won't be printed.\n    ///         // This is because `.do_until()` cancels the future it's given if the\n    ///         // pool is closed first.\n    ///         println!(\"Waited!\");\n    ///\n    ///         Ok(())\n    ///     }).await;\n    ///\n    ///     match res {\n    ///         Ok(Ok(())) => println!(\"Wait succeeded\"),\n    ///         Ok(Err(e)) => println!(\"Error from inside do_until: {e:?}\"),\n    ///         Err(e) => println!(\"Error from do_until: {e:?}\"),\n    ///     }\n    /// });\n    ///\n    /// // This normally wouldn't return until the above statement completed and the connection\n    /// // was returned to the pool. However, thanks to `.do_until()`, the operation was\n    /// // cancelled as soon as we called `.close().await`.\n    /// pool.close().await;\n    ///\n    /// # Ok(())\n    /// # }\n    /// ```\n    pub fn close_event(&self) -> CloseEvent {\n        self.0.close_event()\n    }\n\n    /// Returns the number of connections currently active. This includes idle connections.\n    pub fn size(&self) -> u32 {\n        self.0.size()\n    }\n\n    /// Returns the number of connections active and idle (not in use).\n    pub fn num_idle(&self) -> usize {\n        self.0.num_idle()\n    }\n\n    /// Gets a clone of the connection options for this pool\n    pub fn connect_options(&self) -> Arc<<DB::Connection as Connection>::Options> {\n        self.0\n            .connect_options\n            .read()\n            .expect(\"write-lock holder panicked\")\n            .clone()\n    }\n\n    /// Updates the connection options this pool will use when opening any future connections.  Any\n    /// existing open connection in the pool will be left as-is.\n    pub fn set_connect_options(&self, connect_options: <DB::Connection as Connection>::Options) {\n        // technically write() could also panic if the current thread already holds the lock,\n        // but because this method can't be re-entered by the same thread that shouldn't be a problem\n        let mut guard = self\n            .0\n            .connect_options\n            .write()\n            .expect(\"write-lock holder panicked\");\n        *guard = Arc::new(connect_options);\n    }\n\n    /// Get the options for this pool\n    pub fn options(&self) -> &PoolOptions<DB> {\n        &self.0.options\n    }\n}\n\n/// Returns a new [Pool] tied to the same shared connection pool.\nimpl<DB: Database> Clone for Pool<DB> {\n    fn clone(&self) -> Self {\n        Self(Arc::clone(&self.0))\n    }\n}\n\nimpl<DB: Database> fmt::Debug for Pool<DB> {\n    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {\n        fmt.debug_struct(\"Pool\")\n            .field(\"size\", &self.0.size())\n            .field(\"num_idle\", &self.0.num_idle())\n            .field(\"is_closed\", &self.0.is_closed())\n            .field(\"options\", &self.0.options)\n            .finish()\n    }\n}\n\nimpl CloseEvent {\n    /// Execute the given future until it returns or the pool is closed.\n    ///\n    /// Cancels the future and returns `Err(PoolClosed)` if/when the pool is closed.\n    /// If the pool was already closed, the future is never run.\n    pub async fn do_until<Fut: Future>(&mut self, fut: Fut) -> Result<Fut::Output, Error> {\n        // Check that the pool wasn't closed already.\n        //\n        // We use `poll_immediate()` as it will use the correct waker instead of\n        // a no-op one like `.now_or_never()`, but it won't actually suspend execution here.\n        futures_util::future::poll_immediate(&mut *self)\n            .await\n            .map_or(Ok(()), |_| Err(Error::PoolClosed))?;\n\n        let mut fut = pin!(fut);\n\n        // I find that this is clearer in intent than `futures_util::future::select()`\n        // or `futures_util::select_biased!{}` (which isn't enabled anyway).\n        std::future::poll_fn(|cx| {\n            // Poll `fut` first as the wakeup event is more likely for it than `self`.\n            if let Poll::Ready(ret) = fut.as_mut().poll(cx) {\n                return Poll::Ready(Ok(ret));\n            }\n\n            // Can't really factor out mapping to `Err(Error::PoolClosed)` though it seems like\n            // we should because that results in a different `Ok` type each time.\n            //\n            // Ideally we'd map to something like `Result<!, Error>` but using `!` as a type\n            // is not allowed on stable Rust yet.\n            self.poll_unpin(cx).map(|_| Err(Error::PoolClosed))\n        })\n        .await\n    }\n}\n\nimpl Future for CloseEvent {\n    type Output = ();\n\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        if let Some(listener) = &mut self.listener {\n            ready!(listener.poll_unpin(cx));\n        }\n\n        // `EventListener` doesn't like being polled after it yields, and even if it did it\n        // would probably just wait for the next event, neither of which we want.\n        //\n        // So this way, once we get our close event, we fuse this future to immediately return.\n        self.listener = None;\n\n        Poll::Ready(())\n    }\n}\n\nimpl FusedFuture for CloseEvent {\n    fn is_terminated(&self) -> bool {\n        self.listener.is_none()\n    }\n}\n\n/// get the time between the deadline and now and use that as our timeout\n///\n/// returns `Error::PoolTimedOut` if the deadline is in the past\nfn deadline_as_timeout(deadline: Instant) -> Result<Duration, Error> {\n    deadline\n        .checked_duration_since(Instant::now())\n        .ok_or(Error::PoolTimedOut)\n}\n\n#[test]\n#[allow(dead_code)]\nfn assert_pool_traits() {\n    fn assert_send_sync<T: Send + Sync>() {}\n    fn assert_clone<T: Clone>() {}\n\n    fn assert_pool<DB: Database>() {\n        assert_send_sync::<Pool<DB>>();\n        assert_clone::<Pool<DB>>();\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/pool/options.rs",
    "content": "use crate::connection::Connection;\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::pool::inner::PoolInner;\nuse crate::pool::Pool;\nuse futures_core::future::BoxFuture;\nuse log::LevelFilter;\nuse std::fmt::{self, Debug, Formatter};\nuse std::sync::Arc;\nuse std::time::{Duration, Instant};\n\n/// Configuration options for [`Pool`][super::Pool].\n///\n/// ### Callback Functions: Why Do I Need `Box::pin()`?\n/// Essentially, because it's impossible to write generic bounds that describe a closure\n/// with a higher-ranked lifetime parameter, returning a future with that same lifetime.\n///\n/// Ideally, you could define it like this:\n/// ```rust,ignore\n/// async fn takes_foo_callback(f: impl for<'a> Fn(&'a mut Foo) -> impl Future<'a, Output = ()>)\n/// ```\n///\n/// However, the compiler does not allow using `impl Trait` in the return type of an `impl Fn`.\n///\n/// And if you try to do it like this:\n/// ```rust,ignore\n/// async fn takes_foo_callback<F, Fut>(f: F)\n/// where\n///     F: for<'a> Fn(&'a mut Foo) -> Fut,\n///     Fut: for<'a> Future<Output = ()> + 'a\n/// ```\n///\n/// There's no way to tell the compiler that those two `'a`s should be the same lifetime.\n///\n/// It's possible to make this work with a custom trait, but it's fiddly and requires naming\n///  the type of the closure parameter.\n///\n/// Having the closure return `BoxFuture` allows us to work around this, as all the type information\n/// fits into a single generic parameter.\n///\n/// We still need to `Box` the future internally to give it a concrete type to avoid leaking a type\n/// parameter everywhere, and `Box` is in the prelude so it doesn't need to be manually imported,\n/// so having the closure return `Pin<Box<dyn Future>` directly is the path of least resistance from\n/// the perspectives of both API designer and consumer.\npub struct PoolOptions<DB: Database> {\n    pub(crate) test_before_acquire: bool,\n    pub(crate) after_connect: Option<\n        Arc<\n            dyn Fn(&mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'_, Result<(), Error>>\n                + 'static\n                + Send\n                + Sync,\n        >,\n    >,\n    pub(crate) before_acquire: Option<\n        Arc<\n            dyn Fn(\n                    &mut DB::Connection,\n                    PoolConnectionMetadata,\n                ) -> BoxFuture<'_, Result<bool, Error>>\n                + 'static\n                + Send\n                + Sync,\n        >,\n    >,\n    pub(crate) after_release: Option<\n        Arc<\n            dyn Fn(\n                    &mut DB::Connection,\n                    PoolConnectionMetadata,\n                ) -> BoxFuture<'_, Result<bool, Error>>\n                + 'static\n                + Send\n                + Sync,\n        >,\n    >,\n    pub(crate) max_connections: u32,\n    pub(crate) acquire_time_level: LevelFilter,\n    pub(crate) acquire_slow_level: LevelFilter,\n    pub(crate) acquire_slow_threshold: Duration,\n    pub(crate) acquire_timeout: Duration,\n    pub(crate) min_connections: u32,\n    pub(crate) max_lifetime: Option<Duration>,\n    pub(crate) idle_timeout: Option<Duration>,\n    pub(crate) fair: bool,\n\n    pub(crate) parent_pool: Option<Pool<DB>>,\n}\n\n// Manually implement `Clone` to avoid a trait bound issue.\n//\n// See: https://github.com/launchbadge/sqlx/issues/2548\nimpl<DB: Database> Clone for PoolOptions<DB> {\n    fn clone(&self) -> Self {\n        PoolOptions {\n            test_before_acquire: self.test_before_acquire,\n            after_connect: self.after_connect.clone(),\n            before_acquire: self.before_acquire.clone(),\n            after_release: self.after_release.clone(),\n            max_connections: self.max_connections,\n            acquire_time_level: self.acquire_time_level,\n            acquire_slow_threshold: self.acquire_slow_threshold,\n            acquire_slow_level: self.acquire_slow_level,\n            acquire_timeout: self.acquire_timeout,\n            min_connections: self.min_connections,\n            max_lifetime: self.max_lifetime,\n            idle_timeout: self.idle_timeout,\n            fair: self.fair,\n            parent_pool: self.parent_pool.clone(),\n        }\n    }\n}\n\n/// Metadata for the connection being processed by a [`PoolOptions`] callback.\n#[derive(Debug)] // Don't want to commit to any other trait impls yet.\n#[non_exhaustive] // So we can safely add fields in the future.\npub struct PoolConnectionMetadata {\n    /// The duration since the connection was first opened.\n    ///\n    /// For [`after_connect`][PoolOptions::after_connect], this is [`Duration::ZERO`].\n    pub age: Duration,\n\n    /// The duration that the connection spent in the idle queue.\n    ///\n    /// Only relevant for [`before_acquire`][PoolOptions::before_acquire].\n    /// For other callbacks, this is [`Duration::ZERO`].\n    pub idle_for: Duration,\n}\n\nimpl<DB: Database> Default for PoolOptions<DB> {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl<DB: Database> PoolOptions<DB> {\n    /// Returns a default \"sane\" configuration, suitable for testing or light-duty applications.\n    ///\n    /// Production applications will likely want to at least modify\n    /// [`max_connections`][Self::max_connections].\n    ///\n    /// See the source of this method for the current default values.\n    pub fn new() -> Self {\n        Self {\n            // User-specifiable routines\n            after_connect: None,\n            before_acquire: None,\n            after_release: None,\n            test_before_acquire: true,\n            // A production application will want to set a higher limit than this.\n            max_connections: 10,\n            min_connections: 0,\n            // Logging all acquires is opt-in\n            acquire_time_level: LevelFilter::Off,\n            // Default to warning, because an acquire timeout will be an error\n            acquire_slow_level: LevelFilter::Warn,\n            // Fast enough to catch problems (e.g. a full pool); slow enough\n            // to not flag typical time to add a new connection to a pool.\n            acquire_slow_threshold: Duration::from_secs(2),\n            acquire_timeout: Duration::from_secs(30),\n            idle_timeout: Some(Duration::from_secs(10 * 60)),\n            max_lifetime: Some(Duration::from_secs(30 * 60)),\n            fair: true,\n            parent_pool: None,\n        }\n    }\n\n    /// Set the maximum number of connections that this pool should maintain.\n    ///\n    /// Be mindful of the connection limits for your database as well as other applications\n    /// which may want to connect to the same database (or even multiple instances of the same\n    /// application in high-availability deployments).\n    pub fn max_connections(mut self, max: u32) -> Self {\n        self.max_connections = max;\n        self\n    }\n\n    /// Get the maximum number of connections that this pool should maintain\n    pub fn get_max_connections(&self) -> u32 {\n        self.max_connections\n    }\n\n    /// Set the minimum number of connections to maintain at all times.\n    ///\n    /// When the pool is built, this many connections will be automatically spun up.\n    ///\n    /// If any connection is reaped by [`max_lifetime`] or [`idle_timeout`], or explicitly closed,\n    /// and it brings the connection count below this amount, a new connection will be opened to\n    /// replace it.\n    ///\n    /// This is only done on a best-effort basis, however. The routine that maintains this value\n    /// has a deadline so it doesn't wait forever if the database is being slow or returning errors.\n    ///\n    /// This value is clamped internally to not exceed [`max_connections`].\n    ///\n    /// We've chosen not to assert `min_connections <= max_connections` anywhere\n    /// because it shouldn't break anything internally if the condition doesn't hold,\n    /// and if the application allows either value to be dynamically set\n    /// then it should be checking this condition itself and returning\n    /// a nicer error than a panic anyway.\n    ///\n    /// [`max_lifetime`]: Self::max_lifetime\n    /// [`idle_timeout`]: Self::idle_timeout\n    /// [`max_connections`]: Self::max_connections\n    pub fn min_connections(mut self, min: u32) -> Self {\n        self.min_connections = min;\n        self\n    }\n\n    /// Get the minimum number of connections to maintain at all times.\n    pub fn get_min_connections(&self) -> u32 {\n        self.min_connections\n    }\n\n    /// Enable logging of time taken to acquire a connection from the connection pool via\n    /// [`Pool::acquire()`].\n    ///\n    /// If slow acquire logging is also enabled, this level is used for acquires that are not\n    /// considered slow.\n    pub fn acquire_time_level(mut self, level: LevelFilter) -> Self {\n        self.acquire_time_level = level;\n        self\n    }\n\n    /// Log excessive time taken to acquire a connection at a different log level than time taken\n    /// for faster connection acquires via [`Pool::acquire()`].\n    pub fn acquire_slow_level(mut self, level: LevelFilter) -> Self {\n        self.acquire_slow_level = level;\n        self\n    }\n\n    /// Set a threshold for reporting excessive time taken to acquire a connection from\n    /// the connection pool via [`Pool::acquire()`]. When the threshold is exceeded, a warning is logged.\n    ///\n    /// Defaults to a value that should not typically be exceeded by the pool enlarging\n    /// itself with an additional new connection.\n    pub fn acquire_slow_threshold(mut self, threshold: Duration) -> Self {\n        self.acquire_slow_threshold = threshold;\n        self\n    }\n\n    /// Get the threshold for reporting excessive time taken to acquire a connection via\n    /// [`Pool::acquire()`].\n    pub fn get_acquire_slow_threshold(&self) -> Duration {\n        self.acquire_slow_threshold\n    }\n\n    /// Set the maximum amount of time to spend waiting for a connection in [`Pool::acquire()`].\n    ///\n    /// Caps the total amount of time `Pool::acquire()` can spend waiting across multiple phases:\n    ///\n    /// * First, it may need to wait for a permit from the semaphore, which grants it the privilege\n    ///   of opening a connection or popping one from the idle queue.\n    /// * If an existing idle connection is acquired, by default it will be checked for liveness\n    ///   and integrity before being returned, which may require executing a command on the\n    ///   connection. This can be disabled with [`test_before_acquire(false)`][Self::test_before_acquire].\n    ///     * If [`before_acquire`][Self::before_acquire] is set, that will also be executed.\n    /// * If a new connection needs to be opened, that will obviously require I/O, handshaking,\n    ///   and initialization commands.\n    ///     * If [`after_connect`][Self::after_connect] is set, that will also be executed.\n    pub fn acquire_timeout(mut self, timeout: Duration) -> Self {\n        self.acquire_timeout = timeout;\n        self\n    }\n\n    /// Get the maximum amount of time to spend waiting for a connection in [`Pool::acquire()`].\n    pub fn get_acquire_timeout(&self) -> Duration {\n        self.acquire_timeout\n    }\n\n    /// Set the maximum lifetime of individual connections.\n    ///\n    /// Any connection with a lifetime greater than this will be closed.\n    ///\n    /// When set to `None`, all connections live until either reaped by [`idle_timeout`]\n    /// or explicitly disconnected.\n    ///\n    /// Infinite connections are not recommended due to the unfortunate reality of memory/resource\n    /// leaks on the database-side. It is better to retire connections periodically\n    /// (even if only once daily) to allow the database the opportunity to clean up data structures\n    /// (parse trees, query metadata caches, thread-local storage, etc.) that are associated with a\n    /// session.\n    ///\n    /// [`idle_timeout`]: Self::idle_timeout\n    pub fn max_lifetime(mut self, lifetime: impl Into<Option<Duration>>) -> Self {\n        self.max_lifetime = lifetime.into();\n        self\n    }\n\n    /// Get the maximum lifetime of individual connections.\n    pub fn get_max_lifetime(&self) -> Option<Duration> {\n        self.max_lifetime\n    }\n\n    /// Set a maximum idle duration for individual connections.\n    ///\n    /// Any connection that remains in the idle queue longer than this will be closed.\n    ///\n    /// For usage-based database server billing, this can be a cost saver.\n    pub fn idle_timeout(mut self, timeout: impl Into<Option<Duration>>) -> Self {\n        self.idle_timeout = timeout.into();\n        self\n    }\n\n    /// Get the maximum idle duration for individual connections.\n    pub fn get_idle_timeout(&self) -> Option<Duration> {\n        self.idle_timeout\n    }\n\n    /// If true, the health of a connection will be verified by a call to [`Connection::ping`]\n    /// before returning the connection.\n    ///\n    /// Defaults to `true`.\n    pub fn test_before_acquire(mut self, test: bool) -> Self {\n        self.test_before_acquire = test;\n        self\n    }\n\n    /// Get whether `test_before_acquire` is currently set.\n    pub fn get_test_before_acquire(&self) -> bool {\n        self.test_before_acquire\n    }\n\n    /// If set to `true`, calls to `acquire()` are fair and connections  are issued\n    /// in first-come-first-serve order. If `false`, \"drive-by\" tasks may steal idle connections\n    /// ahead of tasks that have been waiting.\n    ///\n    /// According to `sqlx-bench/benches/pg_pool` this may slightly increase time\n    /// to `acquire()` at low pool contention but at very high contention it helps\n    /// avoid tasks at the head of the waiter queue getting repeatedly preempted by\n    /// these \"drive-by\" tasks and tasks further back in the queue timing out because\n    /// the queue isn't moving.\n    ///\n    /// Currently only exposed for benchmarking; `fair = true` seems to be the superior option\n    /// in most cases.\n    #[doc(hidden)]\n    pub fn __fair(mut self, fair: bool) -> Self {\n        self.fair = fair;\n        self\n    }\n\n    /// Perform an asynchronous action after connecting to the database.\n    ///\n    /// If the operation returns with an error then the error is logged, the connection is closed\n    /// and a new one is opened in its place and the callback is invoked again.\n    ///\n    /// This occurs in a backoff loop to avoid high CPU usage and spamming logs during a transient\n    /// error condition.\n    ///\n    /// Note that this may be called for internally opened connections, such as when maintaining\n    /// [`min_connections`][Self::min_connections], that are then immediately returned to the pool\n    /// without invoking [`after_release`][Self::after_release].\n    ///\n    /// # Example: Additional Parameters\n    /// This callback may be used to set additional configuration parameters\n    /// that are not exposed by the database's `ConnectOptions`.\n    ///\n    /// This example is written for PostgreSQL but can likely be adapted to other databases.\n    ///\n    /// ```no_run\n    /// # async fn f() -> Result<(), Box<dyn std::error::Error>> {\n    /// use sqlx::Executor;\n    /// use sqlx::postgres::PgPoolOptions;\n    ///\n    /// let pool = PgPoolOptions::new()\n    ///     .after_connect(|conn, _meta| Box::pin(async move {\n    ///         // When directly invoking `Executor` methods,\n    ///         // it is possible to execute multiple statements with one call.\n    ///         conn.execute(\"SET application_name = 'your_app'; SET search_path = 'my_schema';\")\n    ///             .await?;\n    ///\n    ///         Ok(())\n    ///     }))\n    ///     .connect(\"postgres:// …\").await?;\n    /// # Ok(())\n    /// # }\n    /// ```\n    ///\n    /// For a discussion on why `Box::pin()` is required, see [the type-level docs][Self].\n    pub fn after_connect<F>(mut self, callback: F) -> Self\n    where\n        // We're passing the `PoolConnectionMetadata` here mostly for future-proofing.\n        // `age` and `idle_for` are obviously not useful for fresh connections.\n        for<'c> F: Fn(&'c mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'c, Result<(), Error>>\n            + 'static\n            + Send\n            + Sync,\n    {\n        self.after_connect = Some(Arc::new(callback));\n        self\n    }\n\n    /// Perform an asynchronous action on a previously idle connection before giving it out.\n    ///\n    /// Alongside the connection, the closure gets [`PoolConnectionMetadata`] which contains\n    /// potentially useful information such as the connection's age and the duration it was\n    /// idle.\n    ///\n    /// If the operation returns `Ok(true)`, the connection is returned to the task that called\n    /// [`Pool::acquire`].\n    ///\n    /// If the operation returns `Ok(false)` or an error, the error is logged (if applicable)\n    /// and then the connection is closed and [`Pool::acquire`] tries again with another idle\n    /// connection. If it runs out of idle connections, it opens a new connection instead.\n    ///\n    /// This is *not* invoked for new connections. Use [`after_connect`][Self::after_connect]\n    /// for those.\n    ///\n    /// # Example: Custom `test_before_acquire` Logic\n    /// If you only want to ping connections if they've been idle a certain amount of time,\n    /// you can implement your own logic here:\n    ///\n    /// This example is written for Postgres but should be trivially adaptable to other databases.\n    /// ```no_run\n    /// # async fn f() -> Result<(), Box<dyn std::error::Error>> {\n    /// use sqlx::{Connection, Executor};\n    /// use sqlx::postgres::PgPoolOptions;\n    ///\n    /// let pool = PgPoolOptions::new()\n    ///     .test_before_acquire(false)\n    ///     .before_acquire(|conn, meta| Box::pin(async move {\n    ///         // One minute\n    ///         if meta.idle_for.as_secs() > 60 {\n    ///             conn.ping().await?;\n    ///         }\n    ///\n    ///         Ok(true)\n    ///     }))\n    ///     .connect(\"postgres:// …\").await?;\n    /// # Ok(())\n    /// # }\n    ///```\n    ///\n    /// For a discussion on why `Box::pin()` is required, see [the type-level docs][Self].\n    pub fn before_acquire<F>(mut self, callback: F) -> Self\n    where\n        for<'c> F: Fn(&'c mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'c, Result<bool, Error>>\n            + 'static\n            + Send\n            + Sync,\n    {\n        self.before_acquire = Some(Arc::new(callback));\n        self\n    }\n\n    /// Perform an asynchronous action on a connection before it is returned to the pool.\n    ///\n    /// Alongside the connection, the closure gets [`PoolConnectionMetadata`] which contains\n    /// potentially useful information such as the connection's age.\n    ///\n    /// If the operation returns `Ok(true)`, the connection is returned to the pool's idle queue.\n    /// If the operation returns `Ok(false)` or an error, the error is logged (if applicable)\n    /// and the connection is closed, allowing a task waiting on [`Pool::acquire`] to\n    /// open a new one in its place.\n    ///\n    /// # Example (Postgres): Close Memory-Hungry Connections\n    /// Instead of relying on [`max_lifetime`][Self::max_lifetime] to close connections,\n    /// we can monitor their memory usage directly and close any that have allocated too much.\n    ///\n    /// Note that this is purely an example showcasing a possible use for this callback\n    /// and may be flawed as it has not been tested.\n    ///\n    /// This example queries [`pg_backend_memory_contexts`](https://www.postgresql.org/docs/current/view-pg-backend-memory-contexts.html)\n    /// which is only allowed for superusers.\n    ///\n    /// ```no_run\n    /// # async fn f() -> Result<(), Box<dyn std::error::Error>> {\n    /// use sqlx::{Connection, Executor};\n    /// use sqlx::postgres::PgPoolOptions;\n    ///\n    /// let pool = PgPoolOptions::new()\n    ///     // Let connections live as long as they want.\n    ///     .max_lifetime(None)\n    ///     .after_release(|conn, meta| Box::pin(async move {\n    ///         // Only check connections older than 6 hours.\n    ///         if meta.age.as_secs() < 6 * 60 * 60 {\n    ///             return Ok(true);\n    ///         }\n    ///\n    ///         let total_memory_usage: i64 = sqlx::query_scalar(\n    ///             \"select sum(used_bytes) from pg_backend_memory_contexts\"\n    ///         )\n    ///         .fetch_one(conn)\n    ///         .await?;\n    ///\n    ///         // Close the connection if the backend memory usage exceeds 256 MiB.\n    ///         Ok(total_memory_usage <= (1 << 28))\n    ///     }))\n    ///     .connect(\"postgres:// …\").await?;\n    /// # Ok(())\n    /// # }\n    pub fn after_release<F>(mut self, callback: F) -> Self\n    where\n        for<'c> F: Fn(&'c mut DB::Connection, PoolConnectionMetadata) -> BoxFuture<'c, Result<bool, Error>>\n            + 'static\n            + Send\n            + Sync,\n    {\n        self.after_release = Some(Arc::new(callback));\n        self\n    }\n\n    /// Set the parent `Pool` from which the new pool will inherit its semaphore.\n    ///\n    /// This is currently an internal-only API.\n    ///\n    /// ### Panics\n    /// If `self.max_connections` is greater than the setting the given pool was created with,\n    /// or `self.fair` differs from the setting the given pool was created with.\n    #[doc(hidden)]\n    pub fn parent(mut self, pool: Pool<DB>) -> Self {\n        self.parent_pool = Some(pool);\n        self\n    }\n\n    /// Create a new pool from this `PoolOptions` and immediately open at least one connection.\n    ///\n    /// This ensures the configuration is correct.\n    ///\n    /// The total number of connections opened is <code>max(1, [min_connections][Self::min_connections])</code>.\n    ///\n    /// Refer to the relevant `ConnectOptions` impl for your database for the expected URL format:\n    ///\n    /// * Postgres: [`PgConnectOptions`][crate::postgres::PgConnectOptions]\n    /// * MySQL: [`MySqlConnectOptions`][crate::mysql::MySqlConnectOptions]\n    /// * SQLite: [`SqliteConnectOptions`][crate::sqlite::SqliteConnectOptions]\n    /// * MSSQL: [`MssqlConnectOptions`][crate::mssql::MssqlConnectOptions]\n    pub async fn connect(self, url: &str) -> Result<Pool<DB>, Error> {\n        self.connect_with(url.parse()?).await\n    }\n\n    /// Create a new pool from this `PoolOptions` and immediately open at least one connection.\n    ///\n    /// This ensures the configuration is correct.\n    ///\n    /// The total number of connections opened is <code>max(1, [min_connections][Self::min_connections])</code>.\n    pub async fn connect_with(\n        self,\n        options: <DB::Connection as Connection>::Options,\n    ) -> Result<Pool<DB>, Error> {\n        // Don't take longer than `acquire_timeout` starting from when this is called.\n        let deadline = Instant::now() + self.acquire_timeout;\n\n        let inner = PoolInner::new_arc(self, options);\n\n        if inner.options.min_connections > 0 {\n            // If the idle reaper is spawned then this will race with the call from that task\n            // and may not report any connection errors.\n            inner.try_min_connections(deadline).await?;\n        }\n\n        // If `min_connections` is nonzero then we'll likely just pull a connection\n        // from the idle queue here, but it should at least get tested first.\n        let conn = inner.acquire().await?;\n        inner.release(conn);\n\n        Ok(Pool(inner))\n    }\n\n    /// Create a new pool from this `PoolOptions`, but don't open any connections right now.\n    ///\n    /// If [`min_connections`][Self::min_connections] is set, a background task will be spawned to\n    /// optimistically establish that many connections for the pool.\n    ///\n    /// Refer to the relevant `ConnectOptions` impl for your database for the expected URL format:\n    ///\n    /// * Postgres: [`PgConnectOptions`][crate::postgres::PgConnectOptions]\n    /// * MySQL: [`MySqlConnectOptions`][crate::mysql::MySqlConnectOptions]\n    /// * SQLite: [`SqliteConnectOptions`][crate::sqlite::SqliteConnectOptions]\n    /// * MSSQL: [`MssqlConnectOptions`][crate::mssql::MssqlConnectOptions]\n    pub fn connect_lazy(self, url: &str) -> Result<Pool<DB>, Error> {\n        Ok(self.connect_lazy_with(url.parse()?))\n    }\n\n    /// Create a new pool from this `PoolOptions`, but don't open any connections right now.\n    ///\n    /// If [`min_connections`][Self::min_connections] is set, a background task will be spawned to\n    /// optimistically establish that many connections for the pool.\n    pub fn connect_lazy_with(self, options: <DB::Connection as Connection>::Options) -> Pool<DB> {\n        // `min_connections` is guaranteed by the idle reaper now.\n        Pool(PoolInner::new_arc(self, options))\n    }\n}\n\nimpl<DB: Database> Debug for PoolOptions<DB> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"PoolOptions\")\n            .field(\"max_connections\", &self.max_connections)\n            .field(\"min_connections\", &self.min_connections)\n            .field(\"connect_timeout\", &self.acquire_timeout)\n            .field(\"max_lifetime\", &self.max_lifetime)\n            .field(\"idle_timeout\", &self.idle_timeout)\n            .field(\"test_before_acquire\", &self.test_before_acquire)\n            .finish()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/query.rs",
    "content": "use std::{future, marker::PhantomData};\n\nuse either::Either;\nuse futures_core::stream::BoxStream;\nuse futures_util::{StreamExt, TryFutureExt, TryStreamExt};\n\nuse crate::arguments::{Arguments, IntoArguments};\nuse crate::database::{Database, HasStatementCache};\nuse crate::encode::Encode;\nuse crate::error::{BoxDynError, Error};\nuse crate::executor::{Execute, Executor};\nuse crate::sql_str::{SqlSafeStr, SqlStr};\nuse crate::statement::Statement;\nuse crate::types::Type;\n\n/// A single SQL query as a prepared statement. Returned by [`query()`].\n#[must_use = \"query must be executed to affect database\"]\npub struct Query<'q, DB: Database, A> {\n    pub(crate) statement: Either<SqlStr, &'q DB::Statement>,\n    pub(crate) arguments: Option<Result<A, BoxDynError>>,\n    pub(crate) database: PhantomData<DB>,\n    pub(crate) persistent: bool,\n}\n\n/// A single SQL query that will map its results to an owned Rust type.\n///\n/// Executes as a prepared statement.\n///\n/// Returned by [`Query::try_map`], `query!()`, etc. Has most of the same methods as [`Query`] but\n/// the return types are changed to reflect the mapping. However, there is no equivalent of\n/// [`Query::execute`] as it doesn't make sense to map the result type and then ignore it.\n///\n/// [`Query::bind`] is also omitted; stylistically we recommend placing your `.bind()` calls\n/// before `.try_map()`. This is also to prevent adding superfluous binds to the result of\n/// `query!()` et al.\n#[must_use = \"query must be executed to affect database\"]\npub struct Map<'q, DB: Database, F, A> {\n    inner: Query<'q, DB, A>,\n    mapper: F,\n}\n\nimpl<'q, DB, A> Execute<'q, DB> for Query<'q, DB, A>\nwhere\n    DB: Database,\n    A: Send + IntoArguments<DB>,\n{\n    #[inline]\n    fn sql(self) -> SqlStr {\n        match self.statement {\n            Either::Right(statement) => statement.sql().clone(),\n            Either::Left(sql) => sql,\n        }\n    }\n\n    fn statement(&self) -> Option<&DB::Statement> {\n        match self.statement {\n            Either::Right(statement) => Some(statement),\n            Either::Left(_) => None,\n        }\n    }\n\n    #[inline]\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        self.arguments\n            .take()\n            .transpose()\n            .map(|option| option.map(IntoArguments::into_arguments))\n    }\n\n    #[inline]\n    fn persistent(&self) -> bool {\n        self.persistent\n    }\n}\n\nimpl<DB: Database> Query<'_, DB, <DB as Database>::Arguments> {\n    /// Bind a value for use with this SQL query.\n    ///\n    /// If the number of times this is called does not match the number of bind parameters that\n    /// appear in the query (`?` for most SQL flavors, `$1 .. $N` for Postgres) then an error\n    /// will be returned when this query is executed.\n    ///\n    /// There is no validation that the value is of the type expected by the query. Most SQL\n    /// flavors will perform type coercion (Postgres will return a database error).\n    ///\n    /// If encoding the value fails, the error is stored and later surfaced when executing the query.\n    pub fn bind<'t, T: Encode<'t, DB> + Type<DB>>(mut self, value: T) -> Self {\n        let Ok(arguments) = self.get_arguments() else {\n            return self;\n        };\n\n        let argument_number = arguments.len() + 1;\n        if let Err(error) = arguments.add(value) {\n            self.arguments = Some(Err(format!(\n                \"Encoding argument ${argument_number} failed: {error}\"\n            )\n            .into()));\n        }\n\n        self\n    }\n\n    /// Like [`Query::bind`] but immediately returns an error if encoding a value failed.\n    pub fn try_bind<'t, T: Encode<'t, DB> + Type<DB>>(\n        &mut self,\n        value: T,\n    ) -> Result<(), BoxDynError> {\n        let arguments = self.get_arguments()?;\n\n        arguments.add(value)\n    }\n\n    fn get_arguments(&mut self) -> Result<&mut DB::Arguments, BoxDynError> {\n        let Some(Ok(arguments)) = self.arguments.as_mut().map(Result::as_mut) else {\n            return Err(\"A previous call to Query::bind produced an error\"\n                .to_owned()\n                .into());\n        };\n\n        Ok(arguments)\n    }\n}\n\nimpl<DB, A> Query<'_, DB, A>\nwhere\n    DB: Database + HasStatementCache,\n{\n    /// If `true`, the statement will get prepared once and cached to the\n    /// connection's statement cache.\n    ///\n    /// If queried once with the flag set to `true`, all subsequent queries\n    /// matching the one with the flag will use the cached statement until the\n    /// cache is cleared.\n    ///\n    /// If `false`, the prepared statement will be closed after execution.\n    ///\n    /// Default: `true`.\n    pub fn persistent(mut self, value: bool) -> Self {\n        self.persistent = value;\n        self\n    }\n}\n\nimpl<'q, DB, A: Send> Query<'q, DB, A>\nwhere\n    DB: Database,\n    A: 'q + IntoArguments<DB>,\n{\n    /// Map each row in the result to another type.\n    ///\n    /// See [`try_map`](Query::try_map) for a fallible version of this method.\n    ///\n    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using\n    /// a [`FromRow`](super::from_row::FromRow) implementation.\n    #[inline]\n    pub fn map<F, O>(\n        self,\n        mut f: F,\n    ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result<O, Error> + Send, A>\n    where\n        F: FnMut(DB::Row) -> O + Send,\n        O: Unpin,\n    {\n        self.try_map(move |row| Ok(f(row)))\n    }\n\n    /// Map each row in the result to another type.\n    ///\n    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using\n    /// a [`FromRow`](super::from_row::FromRow) implementation.\n    #[inline]\n    pub fn try_map<F, O>(self, f: F) -> Map<'q, DB, F, A>\n    where\n        F: FnMut(DB::Row) -> Result<O, Error> + Send,\n        O: Unpin,\n    {\n        Map {\n            inner: self,\n            mapper: f,\n        }\n    }\n\n    /// Execute the query and return the total number of rows affected.\n    #[inline]\n    pub async fn execute<'e, 'c: 'e, E>(self, executor: E) -> Result<DB::QueryResult, Error>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.execute(self).await\n    }\n\n    /// Execute multiple queries and return the rows affected from each query, in a stream.\n    #[inline]\n    #[deprecated = \"Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead. See https://github.com/launchbadge/sqlx/issues/3108 for discussion.\"]\n    pub async fn execute_many<'e, 'c: 'e, E>(\n        self,\n        executor: E,\n    ) -> BoxStream<'e, Result<DB::QueryResult, Error>>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.execute_many(self)\n    }\n\n    /// Execute the query and return the generated results as a stream.\n    #[inline]\n    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<DB::Row, Error>>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.fetch(self)\n    }\n\n    /// Execute multiple queries and return the generated results as a stream.\n    ///\n    /// For each query in the stream, any generated rows are returned first,\n    /// then the `QueryResult` with the number of rows affected.\n    #[inline]\n    #[deprecated = \"Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead. See https://github.com/launchbadge/sqlx/issues/3108 for discussion.\"]\n    // TODO: we'll probably still want a way to get the `DB::QueryResult` at the end of a `fetch()` stream.\n    pub fn fetch_many<'e, 'c: 'e, E>(\n        self,\n        executor: E,\n    ) -> BoxStream<'e, Result<Either<DB::QueryResult, DB::Row>, Error>>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.fetch_many(self)\n    }\n\n    /// Execute the query and return all the resulting rows collected into a [`Vec`].\n    ///\n    /// ### Note: beware result set size.\n    /// This will attempt to collect the full result set of the query into memory.\n    ///\n    /// To avoid exhausting available memory, ensure the result set has a known upper bound,\n    /// e.g. using `LIMIT`.\n    #[inline]\n    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<DB::Row>, Error>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.fetch_all(self).await\n    }\n\n    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    #[inline]\n    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<DB::Row, Error>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.fetch_one(self).await\n    }\n\n    /// Execute the query, returning the first row or `None` otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    #[inline]\n    pub async fn fetch_optional<'e, 'c: 'e, E>(self, executor: E) -> Result<Option<DB::Row>, Error>\n    where\n        'q: 'e,\n        A: 'e,\n        E: Executor<'c, Database = DB>,\n    {\n        executor.fetch_optional(self).await\n    }\n}\n\nimpl<'q, DB, F: Send, A: Send> Execute<'q, DB> for Map<'q, DB, F, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n{\n    #[inline]\n    fn sql(self) -> SqlStr {\n        self.inner.sql()\n    }\n\n    #[inline]\n    fn statement(&self) -> Option<&DB::Statement> {\n        self.inner.statement()\n    }\n\n    #[inline]\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        self.inner.take_arguments()\n    }\n\n    #[inline]\n    fn persistent(&self) -> bool {\n        self.inner.arguments.is_some()\n    }\n}\n\nimpl<'q, DB, F, O, A> Map<'q, DB, F, A>\nwhere\n    DB: Database,\n    F: FnMut(DB::Row) -> Result<O, Error> + Send,\n    O: Send + Unpin,\n    A: 'q + Send + IntoArguments<DB>,\n{\n    /// Map each row in the result to another type.\n    ///\n    /// See [`try_map`](Map::try_map) for a fallible version of this method.\n    ///\n    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using\n    /// a [`FromRow`](super::from_row::FromRow) implementation.\n    #[inline]\n    pub fn map<G, P>(\n        self,\n        mut g: G,\n    ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result<P, Error> + Send, A>\n    where\n        G: FnMut(O) -> P + Send,\n        P: Unpin,\n    {\n        self.try_map(move |data| Ok(g(data)))\n    }\n\n    /// Map each row in the result to another type.\n    ///\n    /// The [`query_as`](super::query_as::query_as) method will construct a mapped query using\n    /// a [`FromRow`](super::from_row::FromRow) implementation.\n    #[inline]\n    pub fn try_map<G, P>(\n        self,\n        mut g: G,\n    ) -> Map<'q, DB, impl FnMut(DB::Row) -> Result<P, Error> + Send, A>\n    where\n        G: FnMut(O) -> Result<P, Error> + Send,\n        P: Unpin,\n    {\n        let mut f = self.mapper;\n        Map {\n            inner: self.inner,\n            mapper: move |row| f(row).and_then(&mut g),\n        }\n    }\n\n    /// Execute the query and return the generated results as a stream.\n    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<O, Error>>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        F: 'e,\n        O: 'e,\n    {\n        // FIXME: this should have used `executor.fetch()` but that's a breaking change\n        // because this technically allows multiple statements in one query string.\n        #[allow(deprecated)]\n        self.fetch_many(executor)\n            .try_filter_map(|step| async move {\n                Ok(match step {\n                    Either::Left(_) => None,\n                    Either::Right(o) => Some(o),\n                })\n            })\n            .boxed()\n    }\n\n    /// Execute multiple queries and return the generated results as a stream\n    /// from each query, in a stream.\n    #[deprecated = \"Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead.\"]\n    pub fn fetch_many<'e, 'c: 'e, E>(\n        mut self,\n        executor: E,\n    ) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        F: 'e,\n        O: 'e,\n    {\n        Box::pin(try_stream! {\n            let mut s = executor.fetch_many(self.inner);\n\n            while let Some(v) = s.try_next().await? {\n                r#yield!(match v {\n                    Either::Left(v) => Either::Left(v),\n                    Either::Right(row) => {\n                        Either::Right((self.mapper)(row)?)\n                    }\n                });\n            }\n\n            Ok(())\n        })\n    }\n\n    /// Execute the query and return all the resulting rows collected into a [`Vec`].\n    ///\n    /// ### Note: beware result set size.\n    /// This will attempt to collect the full result set of the query into memory.\n    ///\n    /// To avoid exhausting available memory, ensure the result set has a known upper bound,\n    /// e.g. using `LIMIT`.\n    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<O>, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        F: 'e,\n        O: 'e,\n    {\n        self.fetch(executor).try_collect().await\n    }\n\n    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<O, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        F: 'e,\n        O: 'e,\n    {\n        self.fetch_optional(executor)\n            .and_then(|row| {\n                future::ready(match row {\n                    Some(row) => Ok(row),\n                    None => Err(Error::RowNotFound),\n                })\n            })\n            .await\n    }\n\n    /// Execute the query, returning the first row or `None` otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    pub async fn fetch_optional<'e, 'c: 'e, E>(mut self, executor: E) -> Result<Option<O>, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        F: 'e,\n        O: 'e,\n    {\n        let row = executor.fetch_optional(self.inner).await?;\n\n        if let Some(row) = row {\n            (self.mapper)(row).map(Some)\n        } else {\n            Ok(None)\n        }\n    }\n}\n\n/// Execute a single SQL query as a prepared statement (explicitly created).\npub fn query_statement<DB>(statement: &DB::Statement) -> Query<'_, DB, <DB as Database>::Arguments>\nwhere\n    DB: Database,\n{\n    Query {\n        database: PhantomData,\n        arguments: Some(Ok(Default::default())),\n        statement: Either::Right(statement),\n        persistent: true,\n    }\n}\n\n/// Execute a single SQL query as a prepared statement (explicitly created), with the given arguments.\npub fn query_statement_with<DB, A>(statement: &DB::Statement, arguments: A) -> Query<'_, DB, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n{\n    Query {\n        database: PhantomData,\n        arguments: Some(Ok(arguments)),\n        statement: Either::Right(statement),\n        persistent: true,\n    }\n}\n\n/// Execute a single SQL query as a prepared statement (transparently cached).\n///\n/// The query string may only contain a single DML statement: `SELECT`, `INSERT`, `UPDATE`, `DELETE` and variants.\n/// The SQLite driver does not currently follow this restriction, but that behavior is deprecated.\n///\n/// The connection will transparently prepare and cache the statement, which means it only needs to be parsed once\n/// in the connection's lifetime, and any generated query plans can be retained.\n/// Thus, the overhead of executing the statement is amortized.\n///\n/// Some third-party databases that speak a supported protocol, e.g. CockroachDB or PGBouncer that speak Postgres,\n/// may have issues with the transparent caching of prepared statements. If you are having trouble,\n/// try setting [`.persistent(false)`][Query::persistent].\n///\n/// See the [`Query`] type for the methods you may call.\n///\n/// ### Dynamic Input: Use Query Parameters (Prevents SQL Injection)\n/// At some point, you'll likely want to include some form of dynamic input in your query, possibly from the user.\n///\n/// Your first instinct might be to do something like this:\n/// ```rust,no_run\n/// # async fn example() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// // Imagine this is input from the user, e.g. a search form on a website.\n/// let user_input = \"possibly untrustworthy input!\";\n///\n/// // DO NOT DO THIS unless you're ABSOLUTELY CERTAIN it's what you need!\n/// let query = format!(\"SELECT * FROM articles WHERE content LIKE '%{user_input}%'\");\n/// // where `conn` is `PgConnection` or `MySqlConnection`\n/// // or some other type that implements `Executor`.\n/// let results = sqlx::query(sqlx::AssertSqlSafe(query)).fetch_all(&mut conn).await?;\n/// # Ok(())\n/// # }\n/// ```\n///\n/// The example above showcases a **SQL injection vulnerability**, because it's trivial for a malicious user to craft\n/// an input that can \"break out\" of the string literal.\n///\n/// For example, if they send the input `foo'; DELETE FROM articles; --`\n/// then your application would send the following to the database server (line breaks added for clarity):\n///\n/// ```sql\n/// SELECT * FROM articles WHERE content LIKE '%foo';\n/// DELETE FROM articles;\n/// --%'\n/// ```\n///\n/// In this case, because this interface *always* uses prepared statements, you would likely be fine because prepared\n/// statements _generally_ (see above) are only allowed to contain a single query. This would simply return an error.\n///\n/// However, it would also break on legitimate user input.\n/// What if someone wanted to search for the string `Alice's Apples`? It would also return an error because\n/// the database would receive a query with a broken string literal (line breaks added for clarity):\n///\n/// ```sql\n/// SELECT * FROM articles WHERE content LIKE '%Alice'\n/// s Apples%'\n/// ```\n///\n/// Of course, it's possible to make this syntactically valid by escaping the apostrophe, but there's a better way.\n///\n/// ##### You should always prefer query parameters for dynamic input.\n///\n/// When using query parameters, you add placeholders to your query where a value\n/// should be substituted at execution time, then call [`.bind()`][Query::bind] with that value.\n///\n/// The syntax for placeholders is unfortunately not standardized and depends on the database:\n///\n/// * Postgres and SQLite: use `$1`, `$2`, `$3`, etc.\n///     * The number is the Nth bound value, starting from one.\n///     * The same placeholder can be used arbitrarily many times to refer to the same bound value.\n///     * SQLite technically supports MySQL's syntax as well as others, but we recommend using this syntax\n///       as SQLx's SQLite driver is written with it in mind.\n/// * MySQL and MariaDB: use `?`.\n///     * Placeholders are purely positional, similar to `println!(\"{}, {}\", foo, bar)`.\n///     * The order of bindings must match the order of placeholders in the query.\n///     * To use a value in multiple places, you must bind it multiple times.\n///\n/// In both cases, the placeholder syntax acts as a variable expression representing the bound value:\n///\n/// ```rust,no_run\n/// # async fn example2() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// let user_input = \"Alice's Apples\";\n///\n/// // Postgres and SQLite\n/// let results = sqlx::query(\n///     // Notice how we only have to bind the argument once and we can use it multiple times:\n///     \"SELECT * FROM articles\n///      WHERE title LIKE '%' || $1 || '%'\n///      OR content LIKE '%' || $1 || '%'\"\n/// )\n///     .bind(user_input)\n///     .fetch_all(&mut conn)\n///     .await?;\n///\n/// // MySQL and MariaDB\n/// let results = sqlx::query(\n///     \"SELECT * FROM articles\n///      WHERE title LIKE CONCAT('%', ?, '%')\n///      OR content LIKE CONCAT('%', ?, '%')\"\n/// )\n///     // If we want to reference the same value multiple times, we have to bind it multiple times:\n///     .bind(user_input)\n///     .bind(user_input)\n///     .fetch_all(&mut conn)\n///     .await?;\n/// # Ok(())\n/// # }\n/// ```\n/// ##### The value bound to a query parameter is entirely separate from the query and does not affect its syntax.\n/// Thus, SQL injection is impossible (barring shenanigans like calling a SQL function that lets you execute a string\n/// as a statement) and *all* strings are valid.\n///\n/// This also means you cannot use query parameters to add conditional SQL fragments.\n///\n/// **SQLx does not substitute placeholders on the client side**. It is done by the database server itself.\n///\n/// ##### SQLx supports many different types for parameter binding, not just strings.\n/// Any type that implements [`Encode<DB>`][Encode] and [`Type<DB>`] can be bound as a parameter.\n///\n/// See [the `types` module][crate::types] (links to `sqlx_core::types` but you should use `sqlx::types`) for details.\n///\n/// As an additional benefit, query parameters are usually sent in a compact binary encoding instead of a human-readable\n/// text encoding, which saves bandwidth.\npub fn query<'a, DB>(sql: impl SqlSafeStr) -> Query<'a, DB, <DB as Database>::Arguments>\nwhere\n    DB: Database,\n{\n    Query {\n        database: PhantomData,\n        arguments: Some(Ok(Default::default())),\n        statement: Either::Left(sql.into_sql_str()),\n        persistent: true,\n    }\n}\n\n/// Execute a SQL query as a prepared statement (transparently cached), with the given arguments.\n///\n/// See [`query()`][query] for details, such as supported syntax.\npub fn query_with<'q, DB, A>(sql: impl SqlSafeStr, arguments: A) -> Query<'q, DB, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n{\n    query_with_result(sql, Ok(arguments))\n}\n\n/// Same as [`query_with`] but is initialized with a Result of arguments instead\npub fn query_with_result<'q, DB, A>(\n    sql: impl SqlSafeStr,\n    arguments: Result<A, BoxDynError>,\n) -> Query<'q, DB, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n{\n    Query {\n        database: PhantomData,\n        arguments: Some(arguments),\n        statement: Either::Left(sql.into_sql_str()),\n        persistent: true,\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/query_as.rs",
    "content": "use std::marker::PhantomData;\n\nuse either::Either;\nuse futures_core::stream::BoxStream;\nuse futures_util::{StreamExt, TryStreamExt};\n\nuse crate::arguments::IntoArguments;\nuse crate::database::{Database, HasStatementCache};\nuse crate::encode::Encode;\nuse crate::error::{BoxDynError, Error};\nuse crate::executor::{Execute, Executor};\nuse crate::from_row::FromRow;\nuse crate::query::{query, query_statement, query_statement_with, query_with_result, Query};\nuse crate::sql_str::{SqlSafeStr, SqlStr};\nuse crate::types::Type;\n\n/// A single SQL query as a prepared statement, mapping results using [`FromRow`].\n/// Returned by [`query_as()`].\n#[must_use = \"query must be executed to affect database\"]\npub struct QueryAs<'q, DB: Database, O, A> {\n    pub(crate) inner: Query<'q, DB, A>,\n    pub(crate) output: PhantomData<O>,\n}\n\nimpl<'q, DB, O: Send, A: Send> Execute<'q, DB> for QueryAs<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: 'q + IntoArguments<DB>,\n{\n    #[inline]\n    fn sql(self) -> SqlStr {\n        self.inner.sql()\n    }\n\n    #[inline]\n    fn statement(&self) -> Option<&DB::Statement> {\n        self.inner.statement()\n    }\n\n    #[inline]\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        self.inner.take_arguments()\n    }\n\n    #[inline]\n    fn persistent(&self) -> bool {\n        self.inner.persistent()\n    }\n}\n\nimpl<'q, DB: Database, O> QueryAs<'q, DB, O, <DB as Database>::Arguments> {\n    /// Bind a value for use with this SQL query.\n    ///\n    /// See [`Query::bind`](Query::bind).\n    pub fn bind<T: 'q + Encode<'q, DB> + Type<DB>>(mut self, value: T) -> Self {\n        self.inner = self.inner.bind(value);\n        self\n    }\n}\n\nimpl<DB, O, A> QueryAs<'_, DB, O, A>\nwhere\n    DB: Database + HasStatementCache,\n{\n    /// If `true`, the statement will get prepared once and cached to the\n    /// connection's statement cache.\n    ///\n    /// If queried once with the flag set to `true`, all subsequent queries\n    /// matching the one with the flag will use the cached statement until the\n    /// cache is cleared.\n    ///\n    /// If `false`, the prepared statement will be closed after execution.\n    ///\n    /// Default: `true`.\n    pub fn persistent(mut self, value: bool) -> Self {\n        self.inner = self.inner.persistent(value);\n        self\n    }\n}\n\n// FIXME: This is very close, nearly 1:1 with `Map`\n// noinspection DuplicatedCode\nimpl<'q, DB, O, A> QueryAs<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: 'q + IntoArguments<DB>,\n    O: Send + Unpin + for<'r> FromRow<'r, DB::Row>,\n{\n    /// Execute the query and return the generated results as a stream.\n    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<O, Error>>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        executor\n            .fetch(self.inner)\n            .map(|row| O::from_row(&row?))\n            .boxed()\n    }\n\n    /// Execute multiple queries and return the generated results as a stream\n    /// from each query, in a stream.\n    #[deprecated = \"Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead. See https://github.com/launchbadge/sqlx/issues/3108 for discussion.\"]\n    pub fn fetch_many<'e, 'c: 'e, E>(\n        self,\n        executor: E,\n    ) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        executor\n            .fetch_many(self.inner)\n            .map(|v| match v {\n                Ok(Either::Right(row)) => O::from_row(&row).map(Either::Right),\n                Ok(Either::Left(v)) => Ok(Either::Left(v)),\n                Err(e) => Err(e),\n            })\n            .boxed()\n    }\n\n    /// Execute the query and return all the resulting rows collected into a [`Vec`].\n    ///\n    /// ### Note: beware result set size.\n    /// This will attempt to collect the full result set of the query into memory.\n    ///\n    /// To avoid exhausting available memory, ensure the result set has a known upper bound,\n    /// e.g. using `LIMIT`.\n    #[inline]\n    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<O>, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        self.fetch(executor).try_collect().await\n    }\n\n    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<O, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        self.fetch_optional(executor)\n            .await\n            .and_then(|row| row.ok_or(Error::RowNotFound))\n    }\n\n    /// Execute the query, returning the first row or `None` otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    pub async fn fetch_optional<'e, 'c: 'e, E>(self, executor: E) -> Result<Option<O>, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        let row = executor.fetch_optional(self.inner).await?;\n        if let Some(row) = row {\n            O::from_row(&row).map(Some)\n        } else {\n            Ok(None)\n        }\n    }\n}\n\n/// Execute a single SQL query as a prepared statement (transparently cached).\n/// Maps rows to Rust types using [`FromRow`].\n///\n/// For details about prepared statements and allowed SQL syntax, see [`query()`][crate::query::query].\n///\n/// ### Example: Map Rows using Tuples\n/// [`FromRow`] is implemented for tuples of up to 16 elements<sup>1</sup>.\n/// Using a tuple of N elements will extract the first N columns from each row using [`Decode`][crate::decode::Decode].\n/// Any extra columns are ignored.\n///\n/// See [`sqlx::types`][crate::types] for the types that can be used.\n///\n/// The `FromRow` implementation will check [`Type::compatible()`] for each column to ensure a compatible type mapping\n/// is used. If an incompatible mapping is detected, an error is returned.\n/// To statically assert compatible types at compile time, see the `query!()` family of macros.\n///\n/// **NOTE**: `SELECT *` is not recommended with this approach because the ordering of returned columns may be different\n/// than expected, especially when using joins.\n///\n/// ```rust,no_run\n/// # async fn example1() -> sqlx::Result<()> {\n/// use sqlx::Connection;\n/// use sqlx::PgConnection;\n///\n/// // This example can be applied to any database as it only uses standard types and syntax.\n/// let mut conn: PgConnection = PgConnection::connect(\"<Database URL>\").await?;\n///\n/// sqlx::raw_sql(\n///     \"CREATE TABLE users(id INTEGER PRIMARY KEY, username TEXT UNIQUE, created_at TIMESTAMPTZ DEFAULT (now()))\"\n/// )\n///     .execute(&mut conn)\n///     .await?;\n///\n/// sqlx::query(\"INSERT INTO users(id, username) VALUES (1, 'alice'), (2, 'bob');\")\n///     .execute(&mut conn)\n///     .await?;\n///\n/// // Get the first row of the result (note the `LIMIT 1` for efficiency)\n/// // This assumes the `time` feature of SQLx is enabled.\n/// let oldest_user: (i32, String, time::OffsetDateTime) = sqlx::query_as(\n///     \"SELECT id, username, created_at FROM users ORDER BY created_at LIMIT 1\"\n/// )\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// assert_eq!(oldest_user.0, 1);\n/// assert_eq!(oldest_user.1, \"alice\");\n///\n/// // Get at most one row\n/// let maybe_charlie: Option<(i32, String, time::OffsetDateTime)> = sqlx::query_as(\n///     \"SELECT id, username, created_at FROM users WHERE username = 'charlie'\"\n/// )\n///     .fetch_optional(&mut conn)\n///     .await?;\n///\n/// assert_eq!(maybe_charlie, None);\n///\n/// // Get all rows in result (Beware of the size of the result set! Consider using `LIMIT`)\n/// let users: Vec<(i32, String, time::OffsetDateTime)> = sqlx::query_as(\n///     \"SELECT id, username, created_at FROM users ORDER BY id\"\n/// )\n///     .fetch_all(&mut conn)\n///     .await?;\n///\n/// println!(\"{users:?}\");\n/// # Ok(())\n/// # }\n/// ```\n///\n/// <sup>1</sup>: It's impossible in Rust to implement a trait for tuples of arbitrary size.\n/// For larger result sets, either use an explicit struct (see below) or use [`query()`][crate::query::query]\n/// instead and extract columns dynamically.\n///\n/// ### Example: Map Rows using `#[derive(FromRow)]`\n/// Using `#[derive(FromRow)]`, we can create a Rust struct to represent our row type\n/// so we can look up fields by name instead of tuple index.\n///\n/// When querying this way, columns will be matched up to the corresponding fields by name, so `SELECT *` is safe to use.\n/// However, you will still want to be aware of duplicate column names in your query when using joins.\n///\n/// The derived `FromRow` implementation will check [`Type::compatible()`] for each column to ensure a compatible type\n/// mapping is used. If an incompatible mapping is detected, an error is returned.\n/// To statically assert compatible types at compile time, see the `query!()` family of macros.\n///\n/// An error will also be returned if an expected column is missing from the result set.\n///\n/// `#[derive(FromRow)]` supports several control attributes which can be used to change how column names and types\n/// are mapped. See [`FromRow`] for details.\n///\n/// Using our previous table definition, we can convert our queries like so:\n/// ```rust,no_run\n/// # async fn example2() -> sqlx::Result<()> {\n/// use sqlx::Connection;\n/// use sqlx::PgConnection;\n///\n/// use time::OffsetDateTime;\n///\n/// #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n/// struct User {\n///     id: i64,\n///     username: String,\n///     // Note: the derive won't compile if the `time` feature of SQLx is not enabled.\n///     created_at: OffsetDateTime,\n/// }\n///\n/// let mut conn: PgConnection = PgConnection::connect(\"<Database URL>\").await?;\n///\n/// // Get the first row of the result (note the `LIMIT 1` for efficiency)\n/// let oldest_user: User = sqlx::query_as(\n///     \"SELECT id, username, created_at FROM users ORDER BY created_at LIMIT 1\"\n/// )\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// assert_eq!(oldest_user.id, 1);\n/// assert_eq!(oldest_user.username, \"alice\");\n///\n/// // Get at most one row\n/// let maybe_charlie: Option<User> = sqlx::query_as(\n///     \"SELECT id, username, created_at FROM users WHERE username = 'charlie'\"\n/// )\n///     .fetch_optional(&mut conn)\n///     .await?;\n///\n/// assert_eq!(maybe_charlie, None);\n///\n/// // Get all rows in result (Beware of the size of the result set! Consider using `LIMIT`)\n/// let users: Vec<User> = sqlx::query_as(\n///     \"SELECT id, username, created_at FROM users ORDER BY id\"\n/// )\n///     .fetch_all(&mut conn)\n///     .await?;\n///\n/// assert_eq!(users[1].id, 2);\n/// assert_eq!(users[1].username, \"bob\");\n/// # Ok(())\n/// # }\n///\n/// ```\n#[inline]\npub fn query_as<'q, DB, O>(sql: impl SqlSafeStr) -> QueryAs<'q, DB, O, <DB as Database>::Arguments>\nwhere\n    DB: Database,\n    O: for<'r> FromRow<'r, DB::Row>,\n{\n    QueryAs {\n        inner: query(sql),\n        output: PhantomData,\n    }\n}\n\n/// Execute a single SQL query, with the given arguments as a prepared statement (transparently cached).\n/// Maps rows to Rust types using [`FromRow`].\n///\n/// For details about prepared statements and allowed SQL syntax, see [`query()`][crate::query::query].\n///\n/// For details about type mapping from [`FromRow`], see [`query_as()`].\n#[inline]\npub fn query_as_with<'q, DB, O, A>(sql: impl SqlSafeStr, arguments: A) -> QueryAs<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n    O: for<'r> FromRow<'r, DB::Row>,\n{\n    query_as_with_result(sql, Ok(arguments))\n}\n\n/// Same as [`query_as_with`] but takes arguments as a Result\n#[inline]\npub fn query_as_with_result<'q, DB, O, A>(\n    sql: impl SqlSafeStr,\n    arguments: Result<A, BoxDynError>,\n) -> QueryAs<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n    O: for<'r> FromRow<'r, DB::Row>,\n{\n    QueryAs {\n        inner: query_with_result(sql, arguments),\n        output: PhantomData,\n    }\n}\n\n// Make a SQL query from a statement, that is mapped to a concrete type.\npub fn query_statement_as<DB, O>(\n    statement: &DB::Statement,\n) -> QueryAs<'_, DB, O, <DB as Database>::Arguments>\nwhere\n    DB: Database,\n    O: for<'r> FromRow<'r, DB::Row>,\n{\n    QueryAs {\n        inner: query_statement(statement),\n        output: PhantomData,\n    }\n}\n\n// Make a SQL query from a statement, with the given arguments, that is mapped to a concrete type.\npub fn query_statement_as_with<'q, DB, O, A>(\n    statement: &'q DB::Statement,\n    arguments: A,\n) -> QueryAs<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n    O: for<'r> FromRow<'r, DB::Row>,\n{\n    QueryAs {\n        inner: query_statement_with(statement, arguments),\n        output: PhantomData,\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/query_builder.rs",
    "content": "//! Runtime query-builder API.\n\nuse std::fmt::Display;\nuse std::fmt::Write;\nuse std::marker::PhantomData;\nuse std::sync::Arc;\n\nuse crate::arguments::{Arguments, IntoArguments};\nuse crate::database::Database;\nuse crate::encode::Encode;\nuse crate::from_row::FromRow;\nuse crate::query::Query;\nuse crate::query_as::QueryAs;\nuse crate::query_scalar::QueryScalar;\nuse crate::sql_str::AssertSqlSafe;\nuse crate::sql_str::SqlSafeStr;\nuse crate::sql_str::SqlStr;\nuse crate::types::Type;\nuse crate::Either;\n\n/// A builder type for constructing queries at runtime.\n///\n/// See [`.push_values()`][Self::push_values] for an example of building a bulk `INSERT` statement.\n/// Note, however, that with Postgres you can get much better performance by using arrays\n/// and `UNNEST()`. [See our FAQ] for details.\n///\n/// [See our FAQ]: https://github.com/launchbadge/sqlx/blob/master/FAQ.md#how-can-i-bind-an-array-to-a-values-clause-how-can-i-do-bulk-inserts\npub struct QueryBuilder<DB>\nwhere\n    DB: Database,\n{\n    query: Arc<String>,\n    init_len: usize,\n    arguments: Option<<DB as Database>::Arguments>,\n}\n\nimpl<DB: Database> Default for QueryBuilder<DB> {\n    fn default() -> Self {\n        QueryBuilder {\n            init_len: 0,\n            query: Default::default(),\n            arguments: Some(Default::default()),\n        }\n    }\n}\n\nconst ERROR: &str = \"BUG: query must not be shared at this point in time\";\n\nimpl<DB: Database> QueryBuilder<DB>\nwhere\n    DB: Database,\n{\n    // `init` is provided because a query will almost always start with a constant fragment\n    // such as `INSERT INTO ...` or `SELECT ...`, etc.\n    /// Start building a query with an initial SQL fragment, which may be an empty string.\n    pub fn new(init: impl Into<String>) -> Self\n    where\n        <DB as Database>::Arguments: Default,\n    {\n        let init = init.into();\n\n        QueryBuilder {\n            init_len: init.len(),\n            query: init.into(),\n            arguments: Some(Default::default()),\n        }\n    }\n\n    /// Construct a `QueryBuilder` with existing SQL and arguments.\n    ///\n    /// ### Note\n    /// This does *not* check if `arguments` is valid for the given SQL.\n    pub fn with_arguments<A>(init: impl Into<String>, arguments: A) -> Self\n    where\n        DB: Database,\n        A: IntoArguments<DB>,\n    {\n        let init = init.into();\n\n        QueryBuilder {\n            init_len: init.len(),\n            query: init.into(),\n            arguments: Some(arguments.into_arguments()),\n        }\n    }\n\n    #[inline]\n    fn sanity_check(&self) {\n        assert!(\n            self.arguments.is_some(),\n            \"QueryBuilder must be reset before reuse after `.build()`\"\n        );\n    }\n\n    /// Append a SQL fragment to the query.\n    ///\n    /// May be a string or anything that implements `Display`.\n    /// You can also use `format_args!()` here to push a formatted string without an intermediate\n    /// allocation.\n    ///\n    /// ### Warning: Beware SQL Injection Vulnerabilities and Untrusted Input!\n    /// You should *not* use this to insert input directly into the query from an untrusted user as\n    /// this can be used by an attacker to extract sensitive data or take over your database.\n    ///\n    /// Security breaches due to SQL injection can cost your organization a lot of money from\n    /// damage control and lost clients, betray the trust of your users in your system, and are just\n    /// plain embarrassing. If you are unfamiliar with the threat that SQL injection imposes, you\n    /// should take some time to learn more about it before proceeding:\n    ///\n    /// * [SQL Injection on OWASP.org](https://owasp.org/www-community/attacks/SQL_Injection)\n    /// * [SQL Injection on Wikipedia](https://en.wikipedia.org/wiki/SQL_injection)\n    ///     * See \"Examples\" for notable instances of security breaches due to SQL injection.\n    ///\n    /// This method does *not* perform sanitization. Instead, you should use\n    /// [`.push_bind()`][Self::push_bind] which inserts a placeholder into the query and then\n    /// sends the possibly untrustworthy value separately (called a \"bind argument\") so that it\n    /// cannot be misinterpreted by the database server.\n    ///\n    /// Note that you should still at least have some sort of sanity checks on the values you're\n    /// sending as that's just good practice and prevent other types of attacks against your system,\n    /// e.g. check that strings aren't too long, numbers are within expected ranges, etc.\n    pub fn push(&mut self, sql: impl Display) -> &mut Self {\n        self.sanity_check();\n        let query: &mut String = Arc::get_mut(&mut self.query).expect(ERROR);\n\n        write!(query, \"{sql}\").expect(\"error formatting `sql`\");\n\n        self\n    }\n\n    /// Push a bind argument placeholder (`?` or `$N` for Postgres) and bind a value to it.\n    ///\n    /// ### Note: Database-specific Limits\n    /// Note that every database has a practical limit on the number of bind parameters\n    /// you can add to a single query. This varies by database.\n    ///\n    /// While you should consult the manual of your specific database version and/or current\n    /// configuration for the exact value as it may be different than listed here,\n    /// the defaults for supported databases as of writing are as follows:\n    ///\n    /// * Postgres and MySQL: 65535\n    ///     * You may find sources that state that Postgres has a limit of 32767,\n    ///       but that is a misinterpretation of the specification by the JDBC driver implementation\n    ///       as discussed in [this Github issue][postgres-limit-issue]. Postgres itself\n    ///       asserts that the number of parameters is in the range `[0, 65535)`.\n    /// * SQLite: 32766 (configurable by [`SQLITE_LIMIT_VARIABLE_NUMBER`])\n    ///     * SQLite prior to 3.32.0: 999\n    /// * MSSQL: 2100\n    ///\n    /// Exceeding these limits may panic (as a sanity check) or trigger a database error at runtime\n    /// depending on the implementation.\n    ///\n    /// [`SQLITE_LIMIT_VARIABLE_NUMBER`]: https://www.sqlite.org/limits.html#max_variable_number\n    /// [postgres-limit-issue]: https://github.com/launchbadge/sqlx/issues/671#issuecomment-687043510\n    pub fn push_bind<'t, T>(&mut self, value: T) -> &mut Self\n    where\n        T: Encode<'t, DB> + Type<DB>,\n    {\n        self.sanity_check();\n\n        let arguments = self\n            .arguments\n            .as_mut()\n            .expect(\"BUG: Arguments taken already\");\n        arguments.add(value).expect(\"Failed to add argument\");\n\n        let query: &mut String = Arc::get_mut(&mut self.query).expect(ERROR);\n        arguments\n            .format_placeholder(query)\n            .expect(\"error in format_placeholder\");\n\n        self\n    }\n\n    /// Start a list separated by `separator`.\n    ///\n    /// The returned type exposes identical [`.push()`][Separated::push] and\n    /// [`.push_bind()`][Separated::push_bind] methods which push `separator` to the query\n    /// before their normal behavior. [`.push_unseparated()`][Separated::push_unseparated] and [`.push_bind_unseparated()`][Separated::push_bind_unseparated] are also\n    /// provided to push a SQL fragment without the separator.\n    ///\n    /// ```rust\n    /// # #[cfg(feature = \"mysql\")] {\n    /// use sqlx::{Execute, MySql, QueryBuilder};\n    /// let foods = vec![\"pizza\".to_string(), \"chips\".to_string()];\n    /// let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(\n    ///     \"SELECT * from food where name in (\"\n    /// );\n    /// // One element vector is handled correctly but an empty vector\n    /// // would cause a sql syntax error\n    /// let mut separated = query_builder.separated(\", \");\n    /// for value_type in foods.iter() {\n    ///   separated.push_bind(value_type);\n    /// }\n    /// separated.push_unseparated(\") \");\n    ///\n    /// let mut query = query_builder.build();\n    /// let sql = query.sql();\n    /// assert!(sql.ends_with(\"in (?, ?) \"));\n    /// # }\n    /// ```\n    pub fn separated<Sep>(&mut self, separator: Sep) -> Separated<'_, DB, Sep>\n    where\n        Sep: Display,\n    {\n        self.sanity_check();\n\n        Separated {\n            query_builder: self,\n            separator,\n            push_separator: false,\n        }\n    }\n\n    // Most of the `QueryBuilder` API is purposefully very low-level but this was a commonly\n    // requested use-case so it made sense to support.\n    /// Push a `VALUES` clause where each item in `tuples` represents a tuple/row in the clause.\n    ///\n    /// This can be used to construct a bulk `INSERT` statement, although keep in mind that all\n    /// databases have some practical limit on the number of bind arguments in a single query.\n    /// See [`.push_bind()`][Self::push_bind] for details.\n    ///\n    /// To be safe, you can do `tuples.into_iter().take(N)` where `N` is the limit for your database\n    /// divided by the number of fields in each tuple; since integer division always rounds down,\n    /// this will ensure that you don't exceed the limit.\n    ///\n    /// ### Notes\n    ///\n    /// If `tuples` is empty, this will likely produce a syntactically invalid query as `VALUES`\n    /// generally expects to be followed by at least 1 tuple.\n    ///\n    /// If `tuples` can have many different lengths, you may want to call\n    /// [`.persistent(false)`][Query::persistent] after [`.build()`][Self::build] to avoid\n    /// filling up the connection's prepared statement cache.\n    ///\n    /// Because the `Arguments` API has a lifetime that must live longer than `Self`, you cannot\n    /// bind by-reference from an iterator unless that iterator yields references that live\n    /// longer than `Self`, even if the specific `Arguments` implementation doesn't actually\n    /// borrow the values (like `MySqlArguments` and `PgArguments` immediately encode the arguments\n    /// and don't borrow them past the `.add()` call).\n    ///\n    /// So basically, if you want to bind by-reference you need an iterator that yields references,\n    /// e.g. if you have values in a `Vec` you can do `.iter()` instead of `.into_iter()`. The\n    /// example below uses an iterator that creates values on the fly\n    /// and so cannot bind by-reference.\n    ///\n    /// ### Example (MySQL)\n    ///\n    /// ```rust\n    /// # #[cfg(feature = \"mysql\")]\n    /// # {\n    /// use sqlx::{Execute, MySql, QueryBuilder};\n    ///\n    /// struct User {\n    ///     id: i32,\n    ///     username: String,\n    ///     email: String,\n    ///     password: String,\n    /// }\n    ///\n    /// // The number of parameters in MySQL must fit in a `u16`.\n    /// const BIND_LIMIT: usize = 65535;\n    ///\n    /// // This would normally produce values forever!\n    /// let users = (0..).map(|i| User {\n    ///     id: i,\n    ///     username: format!(\"test_user_{i}\"),\n    ///     email: format!(\"test-user-{i}@example.com\"),\n    ///     password: format!(\"Test!User@Password#{i}\"),\n    /// });\n    ///\n    /// let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(\n    ///     // Note the trailing space; most calls to `QueryBuilder` don't automatically insert\n    ///     // spaces as that might interfere with identifiers or quoted strings where exact\n    ///     // values may matter.\n    ///     \"INSERT INTO users(id, username, email, password) \"\n    /// );\n    ///\n    /// // Note that `.into_iter()` wasn't needed here since `users` is already an iterator.\n    /// query_builder.push_values(users.take(BIND_LIMIT / 4), |mut b, user| {\n    ///     // If you wanted to bind these by-reference instead of by-value,\n    ///     // you'd need an iterator that yields references that live as long as `query_builder`,\n    ///     // e.g. collect it to a `Vec` first.\n    ///     b.push_bind(user.id)\n    ///         .push_bind(user.username)\n    ///         .push_bind(user.email)\n    ///         .push_bind(user.password);\n    /// });\n    ///\n    /// let mut query = query_builder.build();\n    ///\n    /// // You can then call `query.execute()`, `.fetch_one()`, `.fetch_all()`, etc.\n    /// // For the sake of demonstration though, we're just going to assert the contents\n    /// // of the query.\n    ///\n    /// // These are methods of the `Execute` trait, not normally meant to be called in user code.\n    /// let sql = query.sql();\n    /// let arguments = query.take_arguments().unwrap();\n    ///\n    /// assert!(sql.starts_with(\n    ///     \"INSERT INTO users(id, username, email, password) VALUES (?, ?, ?, ?), (?, ?, ?, ?)\"\n    /// ));\n    ///\n    /// assert!(sql.ends_with(\"(?, ?, ?, ?)\"));\n    ///\n    /// // Not a normally exposed function, only used for this doctest.\n    /// // 65535 / 4 = 16383 (rounded down)\n    /// // 16383 * 4 = 65532\n    /// assert_eq!(arguments.len(), 65532);\n    /// # }\n    /// ```\n    pub fn push_values<I, F>(&mut self, tuples: I, mut push_tuple: F) -> &mut Self\n    where\n        I: IntoIterator,\n        F: FnMut(Separated<'_, DB, &'static str>, I::Item),\n    {\n        self.sanity_check();\n\n        self.push(\"VALUES \");\n\n        let mut separated = self.separated(\", \");\n\n        for tuple in tuples {\n            separated.push(\"(\");\n\n            // use a `Separated` with a separate (hah) internal state\n            push_tuple(separated.query_builder.separated(\", \"), tuple);\n\n            separated.push_unseparated(\")\");\n        }\n\n        debug_assert!(\n            separated.push_separator,\n            \"No value being pushed. QueryBuilder may not build correct sql query!\"\n        );\n\n        separated.query_builder\n    }\n\n    /// Creates `((a, b), (..)` statements, from `tuples`.\n    ///\n    /// This can be used to construct a bulk `SELECT` statement like this:\n    /// ```sql\n    /// SELECT * FROM users WHERE (id, username) IN ((1, \"test_user_1\"), (2, \"test_user_2\"))\n    /// ```\n    ///\n    /// Although keep in mind that all\n    /// databases have some practical limit on the number of bind arguments in a single query.\n    /// See [`.push_bind()`][Self::push_bind] for details.\n    ///\n    /// To be safe, you can do `tuples.into_iter().take(N)` where `N` is the limit for your database\n    /// divided by the number of fields in each tuple; since integer division always rounds down,\n    /// this will ensure that you don't exceed the limit.\n    ///\n    /// ### Notes\n    ///\n    /// If `tuples` is empty, this will likely produce a syntactically invalid query\n    ///\n    /// ### Example (MySQL)\n    ///\n    /// ```rust\n    /// # #[cfg(feature = \"mysql\")]\n    /// # {\n    /// use sqlx::{Execute, MySql, QueryBuilder};\n    ///\n    /// struct User {\n    ///     id: i32,\n    ///     username: String,\n    ///     email: String,\n    ///     password: String,\n    /// }\n    ///\n    /// // The number of parameters in MySQL must fit in a `u16`.\n    /// const BIND_LIMIT: usize = 65535;\n    ///\n    /// // This would normally produce values forever!\n    /// let users = (0..).map(|i| User {\n    ///     id: i,\n    ///     username: format!(\"test_user_{i}\"),\n    ///     email: format!(\"test-user-{i}@example.com\"),\n    ///     password: format!(\"Test!User@Password#{i}\"),\n    /// });\n    ///\n    /// let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(\n    ///     // Note the trailing space; most calls to `QueryBuilder` don't automatically insert\n    ///     // spaces as that might interfere with identifiers or quoted strings where exact\n    ///     // values may matter.\n    ///     \"SELECT * FROM users WHERE (id, username, email, password) in\"\n    /// );\n    ///\n    /// // Note that `.into_iter()` wasn't needed here since `users` is already an iterator.\n    /// query_builder.push_tuples(users.take(BIND_LIMIT / 4), |mut b, user| {\n    ///     // If you wanted to bind these by-reference instead of by-value,\n    ///     // you'd need an iterator that yields references that live as long as `query_builder`,\n    ///     // e.g. collect it to a `Vec` first.\n    ///     b.push_bind(user.id)\n    ///         .push_bind(user.username)\n    ///         .push_bind(user.email)\n    ///         .push_bind(user.password);\n    /// });\n    ///\n    /// let mut query = query_builder.build();\n    ///\n    /// // You can then call `query.execute()`, `.fetch_one()`, `.fetch_all()`, etc.\n    /// // For the sake of demonstration though, we're just going to assert the contents\n    /// // of the query.\n    ///\n    /// // These are methods of the `Execute` trait, not normally meant to be called in user code.\n    /// let sql = query.sql();\n    /// let arguments = query.take_arguments().unwrap();\n    ///\n    /// assert!(sql.starts_with(\n    ///     \"SELECT * FROM users WHERE (id, username, email, password) in ((?, ?, ?, ?), (?, ?, ?, ?), \"\n    /// ));\n    ///\n    /// assert!(sql.ends_with(\"(?, ?, ?, ?)) \"));\n    ///\n    /// // Not a normally exposed function, only used for this doctest.\n    /// // 65535 / 4 = 16383 (rounded down)\n    /// // 16383 * 4 = 65532\n    /// assert_eq!(arguments.len(), 65532);\n    /// }\n    /// ```\n    pub fn push_tuples<I, F>(&mut self, tuples: I, mut push_tuple: F) -> &mut Self\n    where\n        I: IntoIterator,\n        F: FnMut(Separated<'_, DB, &'static str>, I::Item),\n    {\n        self.sanity_check();\n\n        self.push(\" (\");\n\n        let mut separated = self.separated(\", \");\n\n        for tuple in tuples {\n            separated.push(\"(\");\n\n            push_tuple(separated.query_builder.separated(\", \"), tuple);\n\n            separated.push_unseparated(\")\");\n        }\n        separated.push_unseparated(\") \");\n\n        separated.query_builder\n    }\n\n    /// Produce an executable query from this builder.\n    ///\n    /// ### Note: Query is not Checked\n    /// It is your responsibility to ensure that you produce a syntactically correct query here,\n    /// this API has no way to check it for you.\n    ///\n    /// ### Note: Reuse\n    /// You can reuse this builder afterwards to amortize the allocation overhead of the query\n    /// string, however you must call [`.reset()`][Self::reset] first, which returns `Self`\n    /// to the state it was in immediately after [`new()`][Self::new].\n    ///\n    /// Calling any other method but `.reset()` after `.build()` will panic for sanity reasons.\n    pub fn build(&mut self) -> Query<'_, DB, <DB as Database>::Arguments> {\n        self.sanity_check();\n\n        Query {\n            statement: Either::Left(self.sql()),\n            arguments: self.arguments.take().map(Ok),\n            database: PhantomData,\n            persistent: true,\n        }\n    }\n\n    /// Produce an executable query from this builder.\n    ///\n    /// ### Note: Query is not Checked\n    /// It is your responsibility to ensure that you produce a syntactically correct query here,\n    /// this API has no way to check it for you.\n    ///\n    /// ### Note: Reuse\n    /// You can reuse this builder afterwards to amortize the allocation overhead of the query\n    /// string, however you must call [`.reset()`][Self::reset] first, which returns `Self`\n    /// to the state it was in immediately after [`new()`][Self::new].\n    ///\n    /// Calling any other method but `.reset()` after `.build()` will panic for sanity reasons.\n    pub fn build_query_as<'q, T: FromRow<'q, DB::Row>>(\n        &'q mut self,\n    ) -> QueryAs<'q, DB, T, <DB as Database>::Arguments> {\n        QueryAs {\n            inner: self.build(),\n            output: PhantomData,\n        }\n    }\n\n    /// Produce an executable query from this builder.\n    ///\n    /// ### Note: Query is not Checked\n    /// It is your responsibility to ensure that you produce a syntactically correct query here,\n    /// this API has no way to check it for you.\n    ///\n    /// ### Note: Reuse\n    /// You can reuse this builder afterwards to amortize the allocation overhead of the query\n    /// string, however you must call [`.reset()`][Self::reset] first, which returns `Self`\n    /// to the state it was in immediately after [`new()`][Self::new].\n    ///\n    /// Calling any other method but `.reset()` after `.build()` will panic for sanity reasons.\n    pub fn build_query_scalar<'q, T>(\n        &'q mut self,\n    ) -> QueryScalar<'q, DB, T, <DB as Database>::Arguments>\n    where\n        DB: Database,\n        (T,): for<'r> FromRow<'r, DB::Row>,\n    {\n        QueryScalar {\n            inner: self.build_query_as(),\n        }\n    }\n\n    /// Reset this `QueryBuilder` back to its initial state.\n    ///\n    /// The query is truncated to the initial fragment provided to [`new()`][Self::new] and\n    /// the bind arguments are reset.\n    pub fn reset(&mut self) -> &mut Self {\n        // Someone can hold onto a clone of `self.query`, to avoid panicking here we should just\n        // allocate a new `String`.\n        let query: &mut String = Arc::make_mut(&mut self.query);\n        query.truncate(self.init_len);\n        self.arguments = Some(Default::default());\n\n        self\n    }\n\n    /// Get the current build SQL; **note**: may not be syntactically correct.\n    pub fn sql(&self) -> SqlStr {\n        AssertSqlSafe(self.query.clone()).into_sql_str()\n    }\n\n    /// Deconstruct this `QueryBuilder`, returning the built SQL. May not be syntactically correct.\n    pub fn into_string(self) -> String {\n        Arc::unwrap_or_clone(self.query)\n    }\n\n    /// Deconstruct this `QueryBuilder`, returning the built SQL. May not be syntactically correct.\n    pub fn into_sql(self) -> SqlStr {\n        AssertSqlSafe(self.query).into_sql_str()\n    }\n}\n\n/// A wrapper around `QueryBuilder` for creating comma(or other token)-separated lists.\n///\n/// See [`QueryBuilder::separated()`] for details.\n#[allow(explicit_outlives_requirements)]\npub struct Separated<'qb, DB, Sep>\nwhere\n    DB: Database,\n{\n    query_builder: &'qb mut QueryBuilder<DB>,\n    separator: Sep,\n    push_separator: bool,\n}\n\nimpl<DB, Sep> Separated<'_, DB, Sep>\nwhere\n    DB: Database,\n    Sep: Display,\n{\n    /// Push the separator if applicable, and then the given SQL fragment.\n    ///\n    /// See [`QueryBuilder::push()`] for details.\n    pub fn push(&mut self, sql: impl Display) -> &mut Self {\n        if self.push_separator {\n            self.query_builder\n                .push(format_args!(\"{}{}\", self.separator, sql));\n        } else {\n            self.query_builder.push(sql);\n            self.push_separator = true;\n        }\n\n        self\n    }\n\n    /// Push a SQL fragment without a separator.\n    ///\n    /// Simply calls [`QueryBuilder::push()`] directly.\n    pub fn push_unseparated(&mut self, sql: impl Display) -> &mut Self {\n        self.query_builder.push(sql);\n        self\n    }\n\n    /// Push the separator if applicable, then append a bind argument.\n    ///\n    /// See [`QueryBuilder::push_bind()`] for details.\n    pub fn push_bind<'t, T>(&mut self, value: T) -> &mut Self\n    where\n        T: Encode<'t, DB> + Type<DB>,\n    {\n        if self.push_separator {\n            self.query_builder.push(&self.separator);\n        }\n\n        self.query_builder.push_bind(value);\n        self.push_separator = true;\n\n        self\n    }\n\n    /// Push a bind argument placeholder (`?` or `$N` for Postgres) and bind a value to it\n    /// without a separator.\n    ///\n    /// Simply calls [`QueryBuilder::push_bind()`] directly.\n    pub fn push_bind_unseparated<'t, T>(&mut self, value: T) -> &mut Self\n    where\n        T: Encode<'t, DB> + Type<DB>,\n    {\n        self.query_builder.push_bind(value);\n        self\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/query_scalar.rs",
    "content": "use either::Either;\nuse futures_core::stream::BoxStream;\nuse futures_util::{StreamExt, TryFutureExt, TryStreamExt};\n\nuse crate::arguments::IntoArguments;\nuse crate::database::{Database, HasStatementCache};\nuse crate::encode::Encode;\nuse crate::error::{BoxDynError, Error};\nuse crate::executor::{Execute, Executor};\nuse crate::from_row::FromRow;\nuse crate::query_as::{\n    query_as, query_as_with_result, query_statement_as, query_statement_as_with, QueryAs,\n};\nuse crate::sql_str::{SqlSafeStr, SqlStr};\nuse crate::types::Type;\n\n/// A single SQL query as a prepared statement which extracts only the first column of each row.\n/// Returned by [`query_scalar()`].\n#[must_use = \"query must be executed to affect database\"]\npub struct QueryScalar<'q, DB: Database, O, A> {\n    pub(crate) inner: QueryAs<'q, DB, (O,), A>,\n}\n\nimpl<'q, DB: Database, O: Send, A: Send> Execute<'q, DB> for QueryScalar<'q, DB, O, A>\nwhere\n    A: 'q + IntoArguments<DB>,\n{\n    #[inline]\n    fn sql(self) -> SqlStr {\n        self.inner.sql()\n    }\n\n    fn statement(&self) -> Option<&DB::Statement> {\n        self.inner.statement()\n    }\n\n    #[inline]\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        self.inner.take_arguments()\n    }\n\n    #[inline]\n    fn persistent(&self) -> bool {\n        Execute::persistent(&self.inner)\n    }\n}\n\nimpl<'q, DB: Database, O> QueryScalar<'q, DB, O, <DB as Database>::Arguments> {\n    /// Bind a value for use with this SQL query.\n    ///\n    /// See [`Query::bind`](crate::query::Query::bind).\n    pub fn bind<T: 'q + Encode<'q, DB> + Type<DB>>(mut self, value: T) -> Self {\n        self.inner = self.inner.bind(value);\n        self\n    }\n}\n\nimpl<DB, O, A> QueryScalar<'_, DB, O, A>\nwhere\n    DB: Database + HasStatementCache,\n{\n    /// If `true`, the statement will get prepared once and cached to the\n    /// connection's statement cache.\n    ///\n    /// If queried once with the flag set to `true`, all subsequent queries\n    /// matching the one with the flag will use the cached statement until the\n    /// cache is cleared.\n    ///\n    /// If `false`, the prepared statement will be closed after execution.\n    ///\n    /// Default: `true`.\n    pub fn persistent(mut self, value: bool) -> Self {\n        self.inner = self.inner.persistent(value);\n        self\n    }\n}\n\n// FIXME: This is very close, nearly 1:1 with `Map`\n// noinspection DuplicatedCode\nimpl<'q, DB, O, A> QueryScalar<'q, DB, O, A>\nwhere\n    DB: Database,\n    O: Send + Unpin,\n    A: 'q + IntoArguments<DB>,\n    (O,): Send + Unpin + for<'r> FromRow<'r, DB::Row>,\n{\n    /// Execute the query and return the generated results as a stream.\n    #[inline]\n    pub fn fetch<'e, 'c: 'e, E>(self, executor: E) -> BoxStream<'e, Result<O, Error>>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        A: 'e,\n        O: 'e,\n    {\n        self.inner.fetch(executor).map_ok(|it| it.0).boxed()\n    }\n\n    /// Execute multiple queries and return the generated results as a stream\n    /// from each query, in a stream.\n    #[inline]\n    #[deprecated = \"Only the SQLite driver supports multiple statements in one prepared statement and that behavior is deprecated. Use `sqlx::raw_sql()` instead. See https://github.com/launchbadge/sqlx/issues/3108 for discussion.\"]\n    pub fn fetch_many<'e, 'c: 'e, E>(\n        self,\n        executor: E,\n    ) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        A: 'e,\n        O: 'e,\n    {\n        #[allow(deprecated)]\n        self.inner\n            .fetch_many(executor)\n            .map_ok(|v| v.map_right(|it| it.0))\n            .boxed()\n    }\n\n    /// Execute the query and return all the resulting rows collected into a [`Vec`].\n    ///\n    /// ### Note: beware result set size.\n    /// This will attempt to collect the full result set of the query into memory.\n    ///\n    /// To avoid exhausting available memory, ensure the result set has a known upper bound,\n    /// e.g. using `LIMIT`.\n    #[inline]\n    pub async fn fetch_all<'e, 'c: 'e, E>(self, executor: E) -> Result<Vec<O>, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        (O,): 'e,\n        A: 'e,\n    {\n        self.inner\n            .fetch(executor)\n            .map_ok(|it| it.0)\n            .try_collect()\n            .await\n    }\n\n    /// Execute the query, returning the first row or [`Error::RowNotFound`] otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    #[inline]\n    pub async fn fetch_one<'e, 'c: 'e, E>(self, executor: E) -> Result<O, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        self.inner.fetch_one(executor).map_ok(|it| it.0).await\n    }\n\n    /// Execute the query, returning the first row or `None` otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns at most one row\n    /// can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    #[inline]\n    pub async fn fetch_optional<'e, 'c: 'e, E>(self, executor: E) -> Result<Option<O>, Error>\n    where\n        'q: 'e,\n        E: 'e + Executor<'c, Database = DB>,\n        DB: 'e,\n        O: 'e,\n        A: 'e,\n    {\n        Ok(self.inner.fetch_optional(executor).await?.map(|it| it.0))\n    }\n}\n\n/// Execute a single SQL query as a prepared statement (transparently cached) and extract the first\n/// column of each row.\n///\n/// Extracts the first column of each row. Additional columns are ignored.\n/// Any type that implements `Type<DB> + Decode<DB>` may be used.\n///\n/// For details about prepared statements and allowed SQL syntax, see [`query()`][crate::query::query].\n///\n/// ### Example: Simple Lookup\n/// If you just want to look up a single value with little fanfare, this API is perfect for you:\n///\n/// ```rust,no_run\n/// # async fn example_lookup() -> Result<(), Box<dyn std::error::Error>> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// use uuid::Uuid;\n///\n/// // MySQL and MariaDB: use `?`\n/// let user_id: Option<Uuid> = sqlx::query_scalar(\"SELECT user_id FROM users WHERE username = $1\")\n///     .bind(\"alice\")\n///     // Use `&mut` where `conn` is a connection or a transaction, or use `&` for a `Pool`.\n///     .fetch_optional(&mut conn)\n///     .await?;\n///\n/// let user_id = user_id.ok_or(\"unknown user\")?;\n///\n/// # Ok(())\n/// # }\n/// ```\n///\n/// Note how we're using `.fetch_optional()` because the lookup may return no results,\n/// in which case we need to be able to handle an empty result set.\n/// Any rows after the first are ignored.\n///\n/// ### Example: `COUNT`\n/// This API is the easiest way to invoke an aggregate query like `SELECT COUNT(*)`, because you\n/// can conveniently extract the result:\n///\n/// ```rust,no_run\n/// # async fn example_count() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// // Note that `usize` is not used here because unsigned integers are generally not supported,\n/// // and `usize` doesn't even make sense as a mapping because the database server may have\n/// // a completely different architecture.\n/// //\n/// // `i64` is generally a safe choice for `COUNT`.\n/// let count: i64 = sqlx::query_scalar(\"SELECT COUNT(*) FROM users WHERE accepted_tos IS TRUE\")\n///     // Use `&mut` where `conn` is a connection or a transaction, or use `&` for a `Pool`.\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// // The above is functionally equivalent to the following:\n/// // Note the trailing comma, required for the compiler to recognize a 1-element tuple.\n/// let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM users WHERE accepted_tos IS TRUE\")\n///     .fetch_one(&mut conn)\n///     .await?;\n/// # Ok(())\n/// # }\n/// ```\n///\n/// ### Example: `EXISTS`\n/// To test if a row exists or not, use `SELECT EXISTS(<query>)`:\n///\n/// ```rust,no_run\n/// # async fn example_exists() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// // MySQL and MariaDB: use `?`\n/// let username_taken: bool = sqlx::query_scalar(\n///     \"SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)\"\n/// )\n///     .bind(\"alice\")\n///     // Use `&mut` where `conn` is a connection or a transaction, or use `&` for a `Pool`.\n///     .fetch_one(&mut conn)\n///     .await?;\n/// # Ok(())\n/// # }\n/// ```\n///\n/// ### Example: Other Aggregates\n/// Be aware that most other aggregate functions return `NULL` if the query yields an empty set:\n///\n/// ```rust,no_run\n/// # async fn example_aggregate() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// let max_upvotes: Option<i64> = sqlx::query_scalar(\"SELECT MAX(upvotes) FROM posts\")\n///     // Use `&mut` where `conn` is a connection or a transaction, or use `&` for a `Pool`.\n///     .fetch_one(&mut conn)\n///     .await?;\n/// # Ok(())\n/// # }\n/// ```\n///\n/// Note how we're using `Option<i64>` with `.fetch_one()`, because we're always expecting one row\n/// but the column value may be `NULL`. If no rows are returned, this will error.\n///\n/// This is in contrast to using `.fetch_optional()` with `Option<i64>`, which implies that\n/// we're expecting _either_ a row with a `i64` (`BIGINT`), _or_ no rows at all.\n///\n/// Either way, any rows after the first are ignored.\n///\n/// ### Example: `Vec` of Scalars\n/// If you want to collect a single column from a query into a vector,\n/// try `.fetch_all()`:\n///\n/// ```rust,no_run\n/// # async fn example_vec() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// let top_users: Vec<String> = sqlx::query_scalar(\n///     // Note the `LIMIT` to ensure that this doesn't return *all* users:\n///     \"SELECT username\n///      FROM (\n///          SELECT SUM(upvotes) total, user_id\n///          FROM posts\n///          GROUP BY user_id\n///      ) top_users\n///      INNER JOIN users USING (user_id)\n///      ORDER BY total DESC\n///      LIMIT 10\"\n/// )\n///     // Use `&mut` where `conn` is a connection or a transaction, or use `&` for a `Pool`.\n///     .fetch_all(&mut conn)\n///     .await?;\n///\n/// // `top_users` could be empty, too.\n/// assert!(top_users.len() <= 10);\n/// # Ok(())\n/// # }\n/// ```\n#[inline]\npub fn query_scalar<'q, DB, O>(\n    sql: impl SqlSafeStr,\n) -> QueryScalar<'q, DB, O, <DB as Database>::Arguments>\nwhere\n    DB: Database,\n    (O,): for<'r> FromRow<'r, DB::Row>,\n{\n    QueryScalar {\n        inner: query_as(sql),\n    }\n}\n\n/// Execute a SQL query as a prepared statement (transparently cached), with the given arguments,\n/// and extract the first column of each row.\n///\n/// See [`query_scalar()`] for details.\n///\n/// For details about prepared statements and allowed SQL syntax, see [`query()`][crate::query::query].\n#[inline]\npub fn query_scalar_with<'q, DB, O, A>(\n    sql: impl SqlSafeStr,\n    arguments: A,\n) -> QueryScalar<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n    (O,): for<'r> FromRow<'r, DB::Row>,\n{\n    query_scalar_with_result(sql, Ok(arguments))\n}\n\n/// Same as [`query_scalar_with`] but takes arguments as Result\n#[inline]\npub fn query_scalar_with_result<'q, DB, O, A>(\n    sql: impl SqlSafeStr,\n    arguments: Result<A, BoxDynError>,\n) -> QueryScalar<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n    (O,): for<'r> FromRow<'r, DB::Row>,\n{\n    QueryScalar {\n        inner: query_as_with_result(sql, arguments),\n    }\n}\n\n// Make a SQL query from a statement, that is mapped to a concrete value.\npub fn query_statement_scalar<DB, O>(\n    statement: &DB::Statement,\n) -> QueryScalar<'_, DB, O, <DB as Database>::Arguments>\nwhere\n    DB: Database,\n    (O,): for<'r> FromRow<'r, DB::Row>,\n{\n    QueryScalar {\n        inner: query_statement_as(statement),\n    }\n}\n\n// Make a SQL query from a statement, with the given arguments, that is mapped to a concrete value.\npub fn query_statement_scalar_with<'q, DB, O, A>(\n    statement: &'q DB::Statement,\n    arguments: A,\n) -> QueryScalar<'q, DB, O, A>\nwhere\n    DB: Database,\n    A: IntoArguments<DB>,\n    (O,): for<'r> FromRow<'r, DB::Row>,\n{\n    QueryScalar {\n        inner: query_statement_as_with(statement, arguments),\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/raw_sql.rs",
    "content": "use either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\n\nuse crate::database::Database;\nuse crate::error::BoxDynError;\nuse crate::executor::{Execute, Executor};\nuse crate::sql_str::{SqlSafeStr, SqlStr};\nuse crate::Error;\n\n// AUTHOR'S NOTE: I was just going to call this API `sql()` and `Sql`, respectively,\n// but realized that would be extremely annoying to deal with as a SQLite user\n// because IDE smart completion would always recommend the `Sql` type first.\n//\n// It doesn't really need a super convenient name anyway as it's not meant to be used very often.\n\n/// One or more raw SQL statements, separated by semicolons (`;`).\n///\n/// See [`raw_sql()`] for details.\npub struct RawSql(SqlStr);\n\n/// Execute one or more statements as raw SQL, separated by semicolons (`;`).\n///\n/// This interface can be used to execute both DML\n/// (Data Manipulation Language: `SELECT`, `INSERT`, `UPDATE`, `DELETE` and variants)\n/// as well as DDL (Data Definition Language: `CREATE TABLE`, `ALTER TABLE`, etc).\n///\n/// This will not create or cache any prepared statements.\n///\n/// ### Note: singular DML queries, prefer `query()`\n/// This API does not use prepared statements, so usage of it is missing out on their benefits.\n///\n/// Prefer [`query()`][crate::query::query] instead if executing a single query.\n///\n/// It's also possible to combine multiple DML queries into one for use with `query()`:\n///\n/// ##### Common Table Expressions (CTEs: i.e The `WITH` Clause)\n/// Common Table Expressions effectively allow you to define aliases for queries\n/// that can be referenced like temporary tables:\n///\n/// ```sql\n/// WITH inserted_foos AS (\n///     -- Note that only Postgres allows data-modifying statements in CTEs\n///     INSERT INTO foo (bar_id) VALUES ($1)\n///     RETURNING foo_id, bar_id\n/// )\n/// SELECT foo_id, bar_id, bar\n/// FROM inserted_foos\n/// INNER JOIN bar USING (bar_id)\n/// ```\n///\n/// It's important to note that data modifying statements (`INSERT`, `UPDATE`, `DELETE`) may\n/// behave differently than expected. In Postgres, all data-modifying subqueries in a `WITH`\n/// clause execute with the same view of the data; they *cannot* see each other's modifications.\n///\n/// MySQL, MariaDB and SQLite appear to *only* allow `SELECT` statements in CTEs.\n///\n/// See the appropriate entry in your database's manual for details:\n/// * [MySQL](https://dev.mysql.com/doc/refman/8.0/en/with.html)\n///     * [MariaDB](https://mariadb.com/kb/en/with/)\n/// * [Postgres](https://www.postgresql.org/docs/current/queries-with.html)\n/// * [SQLite](https://www.sqlite.org/lang_with.html)\n///\n/// ##### `UNION`/`INTERSECT`/`EXCEPT`\n/// You can also use various set-theory operations on queries,\n/// including `UNION ALL` which simply concatenates their results.\n///\n/// See the appropriate entry in your database's manual for details:\n/// * [MySQL](https://dev.mysql.com/doc/refman/8.0/en/set-operations.html)\n///    * [MariaDB](https://mariadb.com/kb/en/joins-subqueries/)\n/// * [Postgres](https://www.postgresql.org/docs/current/queries-union.html)\n/// * [SQLite](https://www.sqlite.org/lang_select.html#compound_select_statements)\n///\n/// ### Note: query parameters are not supported.\n/// Query parameters require the use of prepared statements which this API does support.\n///\n/// If you require dynamic input data in your SQL, you can use `format!()` but **be very careful\n/// doing this with user input**. SQLx does **not** provide escaping or sanitization for inserting\n/// dynamic input into queries this way.\n///\n/// See [`query()`][crate::query::query] for details.\n///\n/// ### Note: multiple statements and autocommit.\n/// By default, when you use this API to execute a SQL string containing multiple statements\n/// separated by semicolons (`;`), the database server will treat those statements as all executing\n/// within the same transaction block, i.e. wrapped in `BEGIN` and `COMMIT`:\n///\n/// ```rust,no_run\n/// # async fn example() -> sqlx::Result<()> {\n/// let mut conn: sqlx::PgConnection = todo!(\"e.g. PgConnection::connect(<DATABASE URL>)\");\n///\n/// sqlx::raw_sql(\n///     // Imagine we're moving data from one table to another:\n///     // Implicit `BEGIN;`\n///     \"UPDATE foo SET bar = foobar.bar FROM foobar WHERE foobar.foo_id = foo.id;\\\n///      DELETE FROM foobar;\"\n///     // Implicit `COMMIT;`\n/// )\n///    .execute(&mut conn)\n///    .await?;\n///\n/// # Ok(())\n/// # }\n/// ```\n///\n/// If one statement triggers an error, the whole script aborts and rolls back.\n/// You can include explicit `BEGIN` and `COMMIT` statements in the SQL string\n/// to designate units that can be committed or rolled back piecemeal.\n///\n/// This also allows for a rudimentary form of pipelining as the whole SQL string is sent in one go.\n///\n/// ##### MySQL and MariaDB: DDL implicitly commits!\n/// MySQL and MariaDB do not support DDL in transactions. Instead, any active transaction is\n/// immediately and implicitly committed by the database server when executing a DDL statement.\n/// Beware of this behavior.\n///\n/// See [MySQL manual, section 13.3.3: Statements That Cause an Implicit Commit](https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html) for details.\n/// See also: [MariaDB manual: SQL statements That Cause an Implicit Commit](https://mariadb.com/kb/en/sql-statements-that-cause-an-implicit-commit/).\npub fn raw_sql(sql: impl SqlSafeStr) -> RawSql {\n    RawSql(sql.into_sql_str())\n}\n\nimpl<DB: Database> Execute<'_, DB> for RawSql {\n    fn sql(self) -> SqlStr {\n        self.0\n    }\n\n    fn statement(&self) -> Option<&<DB as Database>::Statement> {\n        None\n    }\n\n    fn take_arguments(&mut self) -> Result<Option<<DB as Database>::Arguments>, BoxDynError> {\n        Ok(None)\n    }\n\n    fn persistent(&self) -> bool {\n        false\n    }\n}\n\nimpl RawSql {\n    /// Execute the SQL string and return the total number of rows affected.\n    #[inline]\n    pub async fn execute<'e, E, DB>(self, executor: E) -> crate::Result<DB::QueryResult>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.execute(self).await\n    }\n\n    /// Execute the SQL string. Returns a stream which gives the number of rows affected for each statement in the string.\n    #[inline]\n    pub fn execute_many<'e, E, DB>(\n        self,\n        executor: E,\n    ) -> BoxStream<'e, crate::Result<DB::QueryResult>>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.execute_many(self)\n    }\n\n    /// Execute the SQL string and return the generated results as a stream.\n    ///\n    /// If the string contains multiple statements, their results will be concatenated together.\n    #[inline]\n    pub fn fetch<'e, E, DB>(self, executor: E) -> BoxStream<'e, Result<DB::Row, Error>>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.fetch(self)\n    }\n\n    /// Execute the SQL string and return the generated results as a stream.\n    ///\n    /// For each query in the stream, any generated rows are returned first,\n    /// then the `QueryResult` with the number of rows affected.\n    #[inline]\n    pub fn fetch_many<'e, E, DB>(\n        self,\n        executor: E,\n    ) -> BoxStream<'e, Result<Either<DB::QueryResult, DB::Row>, Error>>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.fetch_many(self)\n    }\n\n    /// Execute the SQL string and return all the resulting rows collected into a [`Vec`].\n    ///\n    /// ### Note: beware result set size.\n    /// This will attempt to collect the full result set of the query into memory.\n    ///\n    /// To avoid exhausting available memory, ensure the result set has a known upper bound,\n    /// e.g. using `LIMIT`.\n    #[inline]\n    pub fn fetch_all<'e, E, DB>(self, executor: E) -> BoxFuture<'e, crate::Result<Vec<DB::Row>>>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.fetch_all(self)\n    }\n\n    /// Execute the SQL string, returning the first row or [`Error::RowNotFound`] otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns\n    /// at most one row can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    #[inline]\n    pub fn fetch_one<'e, E, DB>(self, executor: E) -> BoxFuture<'e, crate::Result<DB::Row>>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.fetch_one(self)\n    }\n\n    /// Execute the SQL string, returning the first row or [`None`] otherwise.\n    ///\n    /// ### Note: for best performance, ensure the query returns at most one row.\n    /// Depending on the driver implementation, if your query can return more than one row,\n    /// it may lead to wasted CPU time and bandwidth on the database server.\n    ///\n    /// Even when the driver implementation takes this into account, ensuring the query returns\n    /// at most one row can result in a more optimal query plan.\n    ///\n    /// If your query has a `WHERE` clause filtering a unique column by a single value, you're good.\n    ///\n    /// Otherwise, you might want to add `LIMIT 1` to your query.\n    #[inline]\n    pub async fn fetch_optional<'e, E, DB>(self, executor: E) -> crate::Result<Option<DB::Row>>\n    where\n        DB: Database,\n        E: Executor<'e, Database = DB>,\n    {\n        executor.fetch_optional(self).await\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/row.rs",
    "content": "use crate::column::{Column, ColumnIndex};\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::error::{mismatched_types, Error};\n\nuse crate::type_checking::TypeChecking;\nuse crate::type_info::TypeInfo;\nuse crate::types::Type;\nuse crate::value::ValueRef;\n\n/// Represents a single row from the database.\n///\n/// [`FromRow`]: crate::row::FromRow\n/// [`Query::fetch`]: crate::query::Query::fetch\npub trait Row: Unpin + Send + Sync + 'static {\n    type Database: Database<Row = Self>;\n\n    /// Returns `true` if this row has no columns.\n    #[inline]\n    fn is_empty(&self) -> bool {\n        self.len() == 0\n    }\n\n    /// Returns the number of columns in this row.\n    #[inline]\n    fn len(&self) -> usize {\n        self.columns().len()\n    }\n\n    /// Gets the column information at `index`.\n    ///\n    /// A string index can be used to access a column by name and a `usize` index\n    /// can be used to access a column by position.\n    ///\n    /// # Panics\n    ///\n    /// Panics if `index` is out of bounds.\n    /// See [`try_column`](Self::try_column) for a non-panicking version.\n    fn column<I>(&self, index: I) -> &<Self::Database as Database>::Column\n    where\n        I: ColumnIndex<Self>,\n    {\n        self.try_column(index).unwrap()\n    }\n\n    /// Gets the column information at `index` or a `ColumnIndexOutOfBounds` error if out of bounds.\n    fn try_column<I>(&self, index: I) -> Result<&<Self::Database as Database>::Column, Error>\n    where\n        I: ColumnIndex<Self>,\n    {\n        Ok(&self.columns()[index.index(self)?])\n    }\n\n    /// Gets all columns in this statement.\n    fn columns(&self) -> &[<Self::Database as Database>::Column];\n\n    /// Index into the database row and decode a single value.\n    ///\n    /// A string index can be used to access a column by name and a `usize` index\n    /// can be used to access a column by position.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the column does not exist or its value cannot be decoded into the requested type.\n    /// See [`try_get`](Self::try_get) for a non-panicking version.\n    ///\n    #[inline]\n    #[track_caller]\n    fn get<'r, T, I>(&'r self, index: I) -> T\n    where\n        I: ColumnIndex<Self>,\n        T: Decode<'r, Self::Database> + Type<Self::Database>,\n    {\n        self.try_get::<T, I>(index).unwrap()\n    }\n\n    /// Index into the database row and decode a single value.\n    ///\n    /// Unlike [`get`](Self::get), this method does not check that the type\n    /// being returned from the database is compatible with the Rust type and blindly tries\n    /// to decode the value.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the column does not exist or its value cannot be decoded into the requested type.\n    /// See [`try_get_unchecked`](Self::try_get_unchecked) for a non-panicking version.\n    ///\n    #[inline]\n    fn get_unchecked<'r, T, I>(&'r self, index: I) -> T\n    where\n        I: ColumnIndex<Self>,\n        T: Decode<'r, Self::Database>,\n    {\n        self.try_get_unchecked::<T, I>(index).unwrap()\n    }\n\n    /// Index into the database row and decode a single value.\n    ///\n    /// A string index can be used to access a column by name and a `usize` index\n    /// can be used to access a column by position.\n    ///\n    /// # Errors\n    ///\n    ///  * [`ColumnNotFound`] if the column by the given name was not found.\n    ///  * [`ColumnIndexOutOfBounds`] if the `usize` index was greater than the number of columns in the row.\n    ///  * [`ColumnDecode`] if the value could not be decoded into the requested type.\n    ///\n    /// [`ColumnDecode`]: Error::ColumnDecode\n    /// [`ColumnNotFound`]: Error::ColumnNotFound\n    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds\n    ///\n    fn try_get<'r, T, I>(&'r self, index: I) -> Result<T, Error>\n    where\n        I: ColumnIndex<Self>,\n        T: Decode<'r, Self::Database> + Type<Self::Database>,\n    {\n        let value = self.try_get_raw(&index)?;\n\n        if !value.is_null() {\n            let ty = value.type_info();\n\n            if !ty.is_null() && !T::compatible(&ty) {\n                return Err(Error::ColumnDecode {\n                    index: format!(\"{index:?}\"),\n                    source: mismatched_types::<Self::Database, T>(&ty),\n                });\n            }\n        }\n\n        T::decode(value).map_err(|source| Error::ColumnDecode {\n            index: format!(\"{index:?}\"),\n            source,\n        })\n    }\n\n    /// Index into the database row and decode a single value.\n    ///\n    /// Unlike [`try_get`](Self::try_get), this method does not check that the type\n    /// being returned from the database is compatible with the Rust type and blindly tries\n    /// to decode the value.\n    ///\n    /// # Errors\n    ///\n    ///  * [`ColumnNotFound`] if the column by the given name was not found.\n    ///  * [`ColumnIndexOutOfBounds`] if the `usize` index was greater than the number of columns in the row.\n    ///  * [`ColumnDecode`] if the value could not be decoded into the requested type.\n    ///\n    /// [`ColumnDecode`]: Error::ColumnDecode\n    /// [`ColumnNotFound`]: Error::ColumnNotFound\n    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds\n    ///\n    #[inline]\n    fn try_get_unchecked<'r, T, I>(&'r self, index: I) -> Result<T, Error>\n    where\n        I: ColumnIndex<Self>,\n        T: Decode<'r, Self::Database>,\n    {\n        let value = self.try_get_raw(&index)?;\n\n        T::decode(value).map_err(|source| Error::ColumnDecode {\n            index: format!(\"{index:?}\"),\n            source,\n        })\n    }\n\n    /// Index into the database row and decode a single value.\n    ///\n    /// # Errors\n    ///\n    ///  * [`ColumnNotFound`] if the column by the given name was not found.\n    ///  * [`ColumnIndexOutOfBounds`] if the `usize` index was greater than the number of columns in the row.\n    ///\n    /// [`ColumnNotFound`]: Error::ColumnNotFound\n    /// [`ColumnIndexOutOfBounds`]: Error::ColumnIndexOutOfBounds\n    ///\n    fn try_get_raw<I>(&self, index: I) -> Result<<Self::Database as Database>::ValueRef<'_>, Error>\n    where\n        I: ColumnIndex<Self>;\n}\n\npub fn debug_row<R>(row: &R, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result\nwhere\n    R: Row,\n    usize: ColumnIndex<R>,\n    <R as Row>::Database: TypeChecking,\n{\n    write!(f, \"{} \", std::any::type_name::<R>())?;\n\n    let mut debug_map = f.debug_map();\n\n    for column in row.columns().iter() {\n        match row.try_get_raw(column.ordinal()) {\n            Ok(value) => {\n                debug_map.entry(\n                    &column.name(),\n                    &<R as Row>::Database::fmt_value_debug(\n                        &<<R as Row>::Database as Database>::ValueRef::to_owned(&value),\n                    ),\n                );\n            }\n            Err(error) => {\n                debug_map.entry(&column.name(), &format!(\"decode error: {error:?}\"));\n            }\n        }\n    }\n\n    debug_map.finish()\n}\n"
  },
  {
    "path": "sqlx-core/src/rt/mod.rs",
    "content": "use std::future::Future;\nuse std::marker::PhantomData;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\nuse std::time::Duration;\n\nuse cfg_if::cfg_if;\n\n#[cfg(feature = \"_rt-async-io\")]\npub mod rt_async_io;\n\n#[cfg(feature = \"_rt-tokio\")]\npub mod rt_tokio;\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"operation timed out\")]\npub struct TimeoutError;\n\npub enum JoinHandle<T> {\n    #[cfg(feature = \"_rt-async-std\")]\n    AsyncStd(async_std::task::JoinHandle<T>),\n\n    #[cfg(feature = \"_rt-tokio\")]\n    Tokio(tokio::task::JoinHandle<T>),\n\n    // Implementation shared by `smol` and `async-global-executor`\n    #[cfg(feature = \"_rt-async-task\")]\n    AsyncTask(Option<async_task::Task<T>>),\n\n    // `PhantomData<T>` requires `T: Unpin`\n    _Phantom(PhantomData<fn() -> T>),\n}\n\npub async fn timeout<F: Future>(duration: Duration, f: F) -> Result<F::Output, TimeoutError> {\n    #[cfg(debug_assertions)]\n    let f = Box::pin(f);\n\n    #[cfg(feature = \"_rt-tokio\")]\n    if rt_tokio::available() {\n        return tokio::time::timeout(duration, f)\n            .await\n            .map_err(|_| TimeoutError);\n    }\n\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-io\")] {\n            rt_async_io::timeout(duration, f).await\n        } else {\n            missing_rt((duration, f))\n        }\n    }\n}\n\npub async fn sleep(duration: Duration) {\n    #[cfg(feature = \"_rt-tokio\")]\n    if rt_tokio::available() {\n        return tokio::time::sleep(duration).await;\n    }\n\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-io\")] {\n            rt_async_io::sleep(duration).await\n        } else {\n            missing_rt(duration)\n        }\n    }\n}\n\n#[track_caller]\npub fn spawn<F>(fut: F) -> JoinHandle<F::Output>\nwhere\n    F: Future + Send + 'static,\n    F::Output: Send + 'static,\n{\n    #[cfg(feature = \"_rt-tokio\")]\n    if let Ok(handle) = tokio::runtime::Handle::try_current() {\n        return JoinHandle::Tokio(handle.spawn(fut));\n    }\n\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-global-executor\")] {\n            JoinHandle::AsyncTask(Some(async_global_executor::spawn(fut)))\n        } else if #[cfg(feature = \"_rt-smol\")] {\n            JoinHandle::AsyncTask(Some(smol::spawn(fut)))\n        } else if #[cfg(feature = \"_rt-async-std\")] {\n            JoinHandle::AsyncStd(async_std::task::spawn(fut))\n        } else {\n            missing_rt(fut)\n        }\n    }\n}\n\n#[track_caller]\npub fn spawn_blocking<F, R>(f: F) -> JoinHandle<R>\nwhere\n    F: FnOnce() -> R + Send + 'static,\n    R: Send + 'static,\n{\n    #[cfg(feature = \"_rt-tokio\")]\n    if let Ok(handle) = tokio::runtime::Handle::try_current() {\n        return JoinHandle::Tokio(handle.spawn_blocking(f));\n    }\n\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-global-executor\")] {\n            JoinHandle::AsyncTask(Some(async_global_executor::spawn_blocking(f)))\n        } else if #[cfg(feature = \"_rt-smol\")] {\n            JoinHandle::AsyncTask(Some(smol::unblock(f)))\n        } else if #[cfg(feature = \"_rt-async-std\")] {\n            JoinHandle::AsyncStd(async_std::task::spawn_blocking(f))\n        } else {\n            missing_rt(f)\n        }\n    }\n}\n\npub async fn yield_now() {\n    #[cfg(feature = \"_rt-tokio\")]\n    if rt_tokio::available() {\n        return tokio::task::yield_now().await;\n    }\n\n    // `smol`, `async-global-executor`, and `async-std` all have the same implementation for this.\n    //\n    // By immediately signaling the waker and then returning `Pending`,\n    // this essentially just moves the task to the back of the runnable queue.\n    //\n    // There isn't any special integration with the runtime, so we can save code by rolling our own.\n    //\n    // (Tokio's implementation is nearly identical too,\n    //  but has additional integration with `tracing` which may be useful for debugging.)\n    let mut yielded = false;\n\n    std::future::poll_fn(|cx| {\n        if !yielded {\n            yielded = true;\n            cx.waker().wake_by_ref();\n            Poll::Pending\n        } else {\n            Poll::Ready(())\n        }\n    })\n    .await\n}\n\n#[track_caller]\npub fn test_block_on<F: Future>(f: F) -> F::Output {\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-io\")] {\n            async_io::block_on(f)\n        } else if #[cfg(feature = \"_rt-tokio\")] {\n            tokio::runtime::Builder::new_current_thread()\n                .enable_all()\n                .build()\n                .expect(\"failed to start Tokio runtime\")\n                .block_on(f)\n        } else {\n            missing_rt(f)\n        }\n    }\n}\n\n#[track_caller]\npub const fn missing_rt<T>(_unused: T) -> ! {\n    if cfg!(feature = \"_rt-tokio\") {\n        panic!(\"this functionality requires a Tokio context\")\n    }\n\n    panic!(\"one of the `runtime` features of SQLx must be enabled\")\n}\n\nimpl<T: Send + 'static> Future for JoinHandle<T> {\n    type Output = T;\n\n    #[track_caller]\n    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {\n        match &mut *self {\n            #[cfg(feature = \"_rt-async-std\")]\n            Self::AsyncStd(handle) => Pin::new(handle).poll(cx),\n\n            #[cfg(feature = \"_rt-async-task\")]\n            Self::AsyncTask(task) => Pin::new(task)\n                .as_pin_mut()\n                .expect(\"BUG: task taken\")\n                .poll(cx),\n\n            #[cfg(feature = \"_rt-tokio\")]\n            Self::Tokio(handle) => Pin::new(handle)\n                .poll(cx)\n                .map(|res| res.expect(\"spawned task panicked\")),\n\n            Self::_Phantom(_) => {\n                let _ = cx;\n                unreachable!(\"runtime should have been checked on spawn\")\n            }\n        }\n    }\n}\n\nimpl<T> Drop for JoinHandle<T> {\n    fn drop(&mut self) {\n        match self {\n            // `async_task` cancels on-drop by default.\n            // We need to explicitly detach to match Tokio and `async-std`.\n            #[cfg(feature = \"_rt-async-task\")]\n            Self::AsyncTask(task) => {\n                if let Some(task) = task.take() {\n                    task.detach();\n                }\n            }\n            _ => (),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/rt/rt_async_io/mod.rs",
    "content": "mod socket;\n\nmod timeout;\npub use timeout::*;\n"
  },
  {
    "path": "sqlx-core/src/rt/rt_async_io/socket.rs",
    "content": "use crate::net::Socket;\n\nuse std::io;\nuse std::io::{Read, Write};\nuse std::net::{Shutdown, TcpStream};\nuse std::task::{Context, Poll};\n\nuse async_io::Async;\n\nuse crate::io::ReadBuf;\n\nimpl Socket for Async<TcpStream> {\n    fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        self.get_ref().read(buf.init_mut())\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.get_ref().write(buf)\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_readable(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_writable(cx)\n    }\n\n    fn poll_shutdown(&mut self, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Poll::Ready(self.get_ref().shutdown(Shutdown::Both))\n    }\n}\n\n#[cfg(unix)]\nimpl Socket for Async<std::os::unix::net::UnixStream> {\n    fn try_read(&mut self, buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        self.get_ref().read(buf.init_mut())\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        self.get_ref().write(buf)\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_readable(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        self.poll_writable(cx)\n    }\n\n    fn poll_shutdown(&mut self, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Poll::Ready(self.get_ref().shutdown(Shutdown::Both))\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/rt/rt_async_io/timeout.rs",
    "content": "use std::{future::Future, pin::pin, time::Duration};\n\nuse futures_util::future::{select, Either};\n\nuse crate::rt::TimeoutError;\n\npub async fn sleep(duration: Duration) {\n    timeout_future(duration).await;\n}\n\npub async fn timeout<F: Future>(duration: Duration, future: F) -> Result<F::Output, TimeoutError> {\n    match select(pin!(future), timeout_future(duration)).await {\n        Either::Left((result, _)) => Ok(result),\n        Either::Right(_) => Err(TimeoutError),\n    }\n}\n\nfn timeout_future(duration: Duration) -> impl Future {\n    async_io::Timer::after(duration)\n}\n"
  },
  {
    "path": "sqlx-core/src/rt/rt_tokio/mod.rs",
    "content": "mod socket;\n\npub fn available() -> bool {\n    tokio::runtime::Handle::try_current().is_ok()\n}\n"
  },
  {
    "path": "sqlx-core/src/rt/rt_tokio/socket.rs",
    "content": "use std::io;\nuse std::pin::Pin;\nuse std::task::{Context, Poll};\n\nuse tokio::io::AsyncWrite;\nuse tokio::net::TcpStream;\n\nuse crate::io::ReadBuf;\nuse crate::net::Socket;\n\nimpl Socket for TcpStream {\n    fn try_read(&mut self, mut buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        // Requires `&mut impl BufMut`\n        self.try_read_buf(&mut buf)\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        (*self).try_write(buf)\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (*self).poll_read_ready(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (*self).poll_write_ready(cx)\n    }\n\n    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(self).poll_shutdown(cx)\n    }\n}\n\n#[cfg(unix)]\nimpl Socket for tokio::net::UnixStream {\n    fn try_read(&mut self, mut buf: &mut dyn ReadBuf) -> io::Result<usize> {\n        self.try_read_buf(&mut buf)\n    }\n\n    fn try_write(&mut self, buf: &[u8]) -> io::Result<usize> {\n        (*self).try_write(buf)\n    }\n\n    fn poll_read_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (*self).poll_read_ready(cx)\n    }\n\n    fn poll_write_ready(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        (*self).poll_write_ready(cx)\n    }\n\n    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {\n        Pin::new(self).poll_shutdown(cx)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/sql_str.rs",
    "content": "use std::borrow::{Borrow, Cow};\nuse std::hash::{Hash, Hasher};\nuse std::sync::Arc;\n\n/// A SQL string that is safe to execute on a database connection.\n///\n/// A \"safe\" SQL string is one that is unlikely to contain a [SQL injection vulnerability][injection].\n///\n/// In practice, this means a string type that is unlikely to contain dynamic data or user input.\n///\n/// `&'static str` is the only string type that satisfies the requirements of this trait\n/// (ignoring [`String::leak()`] which has niche use-cases) and so is the only string type that\n/// natively implements this trait by default.\n///\n/// For other string types, use [`AssertSqlSafe`] to assert this property.\n/// This is the only intended way to pass an owned `String` to [`query()`] and its related functions\n/// as well as [`raw_sql()`].\n///\n/// The maintainers of SQLx take no responsibility for any data leaks or loss resulting from misuse\n/// of this API.\n///\n/// ### Motivation\n/// This is designed to act as a speed bump against naively using `format!()` to add dynamic data\n/// or user input to a query, which is a classic vector for SQL injection as SQLx does not\n/// provide any sort of escaping or sanitization (which would have to be specially implemented\n/// for each database flavor/locale).\n///\n/// The recommended way to incorporate dynamic data or user input in a query is to use\n/// bind parameters, which requires the query to execute as a prepared statement.\n/// See [`query()`] for details.\n///\n/// This trait and [`AssertSqlSafe`] are intentionally analogous to\n/// [`std::panic::UnwindSafe`] and [`std::panic::AssertUnwindSafe`], respectively.\n///\n/// [injection]: https://en.wikipedia.org/wiki/SQL_injection\n/// [`query()`]: crate::query::query\n/// [`raw_sql()`]: crate::raw_sql::raw_sql\n#[diagnostic::on_unimplemented(\n    label = \"dynamic SQL string\",\n    message = \"dynamic SQL strings should be audited for possible injections\",\n    note = \"prefer literal SQL strings with bind parameters or `QueryBuilder` to add dynamic data to a query.\n\nTo bypass this error, manually audit for potential injection vulnerabilities and wrap with `AssertSqlSafe()`.\nFor details, see the docs for `SqlSafeStr`.\\n\",\n    note = \"this trait is only implemented for `&'static str`, not all `&str` like the compiler error may suggest\"\n)]\npub trait SqlSafeStr {\n    /// Convert `self` to a [`SqlStr`].\n    fn into_sql_str(self) -> SqlStr;\n}\n\nimpl SqlSafeStr for &'static str {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        SqlStr(Repr::Static(self))\n    }\n}\n\n/// Assert that a query string is safe to execute on a database connection.\n///\n/// Using this API means that **you** have made sure that the string contents do not contain a\n/// [SQL injection vulnerability][injection]. It means that, if the string was constructed\n/// dynamically, and/or from user input, you have taken care to sanitize the input yourself.\n/// SQLx does not provide any sort of sanitization; the design of SQLx prefers the use\n/// of prepared statements for dynamic input.\n///\n/// The maintainers of SQLx take no responsibility for any data leaks or loss resulting from misuse\n/// of this API. **Use at your own risk.**\n///\n/// Note that `&'static str` implements [`SqlSafeStr`] directly and so does not need to be wrapped\n/// with this type.\n///\n/// [injection]: https://en.wikipedia.org/wiki/SQL_injection\npub struct AssertSqlSafe<T>(pub T);\n\n/// Note: copies the string.\n///\n/// It is recommended to pass one of the supported owned string types instead.\nimpl SqlSafeStr for AssertSqlSafe<&str> {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        SqlStr(Repr::Arced(self.0.into()))\n    }\n}\nimpl SqlSafeStr for AssertSqlSafe<String> {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        SqlStr(Repr::Owned(self.0))\n    }\n}\n\nimpl SqlSafeStr for AssertSqlSafe<Box<str>> {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        SqlStr(Repr::Boxed(self.0))\n    }\n}\n\n// Note: this is not implemented for `Rc<str>` because it would make `QueryString: !Send`.\nimpl SqlSafeStr for AssertSqlSafe<Arc<str>> {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        SqlStr(Repr::Arced(self.0))\n    }\n}\n\nimpl SqlSafeStr for AssertSqlSafe<Arc<String>> {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        SqlStr(Repr::ArcString(self.0))\n    }\n}\n\nimpl SqlSafeStr for AssertSqlSafe<Cow<'static, str>> {\n    fn into_sql_str(self) -> SqlStr {\n        match self.0 {\n            Cow::Borrowed(str) => str.into_sql_str(),\n            Cow::Owned(str) => AssertSqlSafe(str).into_sql_str(),\n        }\n    }\n}\n\n/// A SQL string that is ready to execute on a database connection.\n///\n/// This is essentially `Cow<'static, str>` but which can be constructed from additional types\n/// without copying.\n///\n/// See [`SqlSafeStr`] for details.\n#[derive(Debug)]\npub struct SqlStr(Repr);\n\n#[derive(Debug)]\nenum Repr {\n    /// We need a variant to memoize when we already have a static string, so we don't copy it.\n    Static(&'static str),\n    /// Thanks to the new niche in `String`, this doesn't increase the size beyond 3 words.\n    /// We essentially get all these variants for free.\n    Owned(String),\n    Boxed(Box<str>),\n    Arced(Arc<str>),\n    /// Allows for dynamic shared ownership with `query_builder`.\n    ArcString(Arc<String>),\n}\n\nimpl Clone for SqlStr {\n    fn clone(&self) -> Self {\n        Self(match &self.0 {\n            Repr::Static(s) => Repr::Static(s),\n            Repr::Arced(s) => Repr::Arced(s.clone()),\n            // If `.clone()` gets called once, assume it might get called again.\n            _ => Repr::Arced(self.as_str().into()),\n        })\n    }\n}\n\nimpl SqlSafeStr for SqlStr {\n    #[inline]\n    fn into_sql_str(self) -> SqlStr {\n        self\n    }\n}\n\nimpl SqlStr {\n    /// Borrow the inner query string.\n    #[inline]\n    pub fn as_str(&self) -> &str {\n        match &self.0 {\n            Repr::Static(s) => s,\n            Repr::Owned(s) => s,\n            Repr::Boxed(s) => s,\n            Repr::Arced(s) => s,\n            Repr::ArcString(s) => s,\n        }\n    }\n\n    pub const fn from_static(sql: &'static str) -> Self {\n        SqlStr(Repr::Static(sql))\n    }\n}\n\nimpl AsRef<str> for SqlStr {\n    #[inline]\n    fn as_ref(&self) -> &str {\n        self.as_str()\n    }\n}\n\nimpl Borrow<str> for SqlStr {\n    #[inline]\n    fn borrow(&self) -> &str {\n        self.as_str()\n    }\n}\n\nimpl<T> PartialEq<T> for SqlStr\nwhere\n    T: AsRef<str>,\n{\n    fn eq(&self, other: &T) -> bool {\n        self.as_str() == other.as_ref()\n    }\n}\n\nimpl Eq for SqlStr {}\n\nimpl Hash for SqlStr {\n    fn hash<H: Hasher>(&self, state: &mut H) {\n        self.as_str().hash(state)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/statement.rs",
    "content": "use crate::arguments::IntoArguments;\nuse crate::column::ColumnIndex;\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::from_row::FromRow;\nuse crate::query::Query;\nuse crate::query_as::QueryAs;\nuse crate::query_scalar::QueryScalar;\nuse crate::sql_str::SqlStr;\nuse either::Either;\n\n/// An explicitly prepared statement.\n///\n/// Statements are prepared and cached by default, per connection. This type allows you to\n/// look at that cache in-between the statement being prepared and it being executed. This contains\n/// the expected columns to be returned and the expected parameter types (if available).\n///\n/// Statements can be re-used with any connection and on first-use it will be re-prepared and\n/// cached within the connection.\npub trait Statement: Send + Sync + Clone {\n    type Database: Database;\n\n    /// Get the original SQL text used to create this statement.\n    fn into_sql(self) -> SqlStr;\n\n    /// Get the original SQL text used to create this statement.\n    fn sql(&self) -> &SqlStr;\n\n    /// Get the expected parameters for this statement.\n    ///\n    /// The information returned depends on what is available from the driver. SQLite can\n    /// only tell us the number of parameters. PostgreSQL can give us full type information.\n    fn parameters(&self) -> Option<Either<&[<Self::Database as Database>::TypeInfo], usize>>;\n\n    /// Get the columns expected to be returned by executing this statement.\n    fn columns(&self) -> &[<Self::Database as Database>::Column];\n\n    /// Gets the column information at `index`.\n    ///\n    /// A string index can be used to access a column by name and a `usize` index\n    /// can be used to access a column by position.\n    ///\n    /// # Panics\n    ///\n    /// Panics if `index` is out of bounds.\n    /// See [`try_column`](Self::try_column) for a non-panicking version.\n    fn column<I>(&self, index: I) -> &<Self::Database as Database>::Column\n    where\n        I: ColumnIndex<Self>,\n    {\n        self.try_column(index).unwrap()\n    }\n\n    /// Gets the column information at `index` or a `ColumnIndexOutOfBounds` error if out of bounds.\n    fn try_column<I>(&self, index: I) -> Result<&<Self::Database as Database>::Column, Error>\n    where\n        I: ColumnIndex<Self>,\n    {\n        Ok(&self.columns()[index.index(self)?])\n    }\n\n    fn query(&self) -> Query<'_, Self::Database, <Self::Database as Database>::Arguments>;\n\n    fn query_with<A>(&self, arguments: A) -> Query<'_, Self::Database, A>\n    where\n        A: IntoArguments<Self::Database>;\n\n    fn query_as<O>(\n        &self,\n    ) -> QueryAs<'_, Self::Database, O, <Self::Database as Database>::Arguments>\n    where\n        O: for<'r> FromRow<'r, <Self::Database as Database>::Row>;\n\n    fn query_as_with<'s, O, A>(&'s self, arguments: A) -> QueryAs<'s, Self::Database, O, A>\n    where\n        O: for<'r> FromRow<'r, <Self::Database as Database>::Row>,\n        A: IntoArguments<Self::Database>;\n\n    fn query_scalar<O>(\n        &self,\n    ) -> QueryScalar<'_, Self::Database, O, <Self::Database as Database>::Arguments>\n    where\n        (O,): for<'r> FromRow<'r, <Self::Database as Database>::Row>;\n\n    fn query_scalar_with<'s, O, A>(&'s self, arguments: A) -> QueryScalar<'s, Self::Database, O, A>\n    where\n        (O,): for<'r> FromRow<'r, <Self::Database as Database>::Row>,\n        A: IntoArguments<Self::Database>;\n}\n\n#[macro_export]\nmacro_rules! impl_statement_query {\n    ($A:ty) => {\n        #[inline]\n        fn query(&self) -> $crate::query::Query<'_, Self::Database, $A> {\n            $crate::query::query_statement(self)\n        }\n\n        #[inline]\n        fn query_with<A>(&self, arguments: A) -> $crate::query::Query<'_, Self::Database, A>\n        where\n            A: $crate::arguments::IntoArguments<Self::Database>,\n        {\n            $crate::query::query_statement_with(self, arguments)\n        }\n\n        #[inline]\n        fn query_as<O>(\n            &self,\n        ) -> $crate::query_as::QueryAs<\n            '_,\n            Self::Database,\n            O,\n            <Self::Database as $crate::database::Database>::Arguments,\n        >\n        where\n            O: for<'r> $crate::from_row::FromRow<\n                'r,\n                <Self::Database as $crate::database::Database>::Row,\n            >,\n        {\n            $crate::query_as::query_statement_as(self)\n        }\n\n        #[inline]\n        fn query_as_with<'s, O, A>(\n            &'s self,\n            arguments: A,\n        ) -> $crate::query_as::QueryAs<'s, Self::Database, O, A>\n        where\n            O: for<'r> $crate::from_row::FromRow<\n                'r,\n                <Self::Database as $crate::database::Database>::Row,\n            >,\n            A: $crate::arguments::IntoArguments<Self::Database>,\n        {\n            $crate::query_as::query_statement_as_with(self, arguments)\n        }\n\n        #[inline]\n        fn query_scalar<O>(\n            &self,\n        ) -> $crate::query_scalar::QueryScalar<\n            '_,\n            Self::Database,\n            O,\n            <Self::Database as $crate::database::Database>::Arguments,\n        >\n        where\n            (O,): for<'r> $crate::from_row::FromRow<\n                'r,\n                <Self::Database as $crate::database::Database>::Row,\n            >,\n        {\n            $crate::query_scalar::query_statement_scalar(self)\n        }\n\n        #[inline]\n        fn query_scalar_with<'s, O, A>(\n            &'s self,\n            arguments: A,\n        ) -> $crate::query_scalar::QueryScalar<'s, Self::Database, O, A>\n        where\n            (O,): for<'r> $crate::from_row::FromRow<\n                'r,\n                <Self::Database as $crate::database::Database>::Row,\n            >,\n            A: $crate::arguments::IntoArguments<Self::Database>,\n        {\n            $crate::query_scalar::query_statement_scalar_with(self, arguments)\n        }\n    };\n}\n"
  },
  {
    "path": "sqlx-core/src/sync.rs",
    "content": "use cfg_if::cfg_if;\n\n// For types with identical signatures that don't require runtime support,\n// we can just arbitrarily pick one to use based on what's enabled.\n//\n// We'll generally lean towards Tokio's types as those are more featureful\n// (including `tokio-console` support) and more widely deployed.\n\npub struct AsyncSemaphore {\n    // We use the semaphore from futures-intrusive as the one from async-lock\n    // is missing the ability to add arbitrary permits, and is not guaranteed to be fair:\n    // * https://github.com/smol-rs/async-lock/issues/22\n    // * https://github.com/smol-rs/async-lock/issues/23\n    //\n    // We're on the look-out for a replacement, however, as futures-intrusive is not maintained\n    // and there are some soundness concerns (although it turns out any intrusive future is unsound\n    // in MIRI due to the necessitated mutable aliasing):\n    // https://github.com/launchbadge/sqlx/issues/1668\n    #[cfg(all(\n        any(\n            feature = \"_rt-async-global-executor\",\n            feature = \"_rt-async-std\",\n            feature = \"_rt-smol\"\n        ),\n        not(feature = \"_rt-tokio\")\n    ))]\n    inner: futures_intrusive::sync::Semaphore,\n\n    #[cfg(feature = \"_rt-tokio\")]\n    inner: tokio::sync::Semaphore,\n}\n\nimpl AsyncSemaphore {\n    #[track_caller]\n    pub fn new(fair: bool, permits: usize) -> Self {\n        if cfg!(not(any(\n            feature = \"_rt-async-global-executor\",\n            feature = \"_rt-async-std\",\n            feature = \"_rt-smol\",\n            feature = \"_rt-tokio\"\n        ))) {\n            crate::rt::missing_rt((fair, permits));\n        }\n\n        AsyncSemaphore {\n            #[cfg(all(\n                any(\n                    feature = \"_rt-async-global-executor\",\n                    feature = \"_rt-async-std\",\n                    feature = \"_rt-smol\"\n                ),\n                not(feature = \"_rt-tokio\")\n            ))]\n            inner: futures_intrusive::sync::Semaphore::new(fair, permits),\n            #[cfg(feature = \"_rt-tokio\")]\n            inner: {\n                debug_assert!(fair, \"Tokio only has fair permits\");\n                tokio::sync::Semaphore::new(permits)\n            },\n        }\n    }\n\n    pub fn permits(&self) -> usize {\n        cfg_if! {\n            if #[cfg(all(\n                any(\n                    feature = \"_rt-async-global-executor\",\n                    feature = \"_rt-async-std\",\n                    feature = \"_rt-smol\"\n                ),\n                not(feature = \"_rt-tokio\")\n            ))] {\n                self.inner.permits()\n            } else if #[cfg(feature = \"_rt-tokio\")] {\n                self.inner.available_permits()\n            } else {\n                crate::rt::missing_rt(())\n            }\n        }\n    }\n\n    pub async fn acquire(&self, permits: u32) -> AsyncSemaphoreReleaser<'_> {\n        cfg_if! {\n            if #[cfg(all(\n                any(\n                    feature = \"_rt-async-global-executor\",\n                    feature = \"_rt-async-std\",\n                    feature = \"_rt-smol\"\n                ),\n                not(feature = \"_rt-tokio\")\n            ))] {\n                AsyncSemaphoreReleaser {\n                    inner: self.inner.acquire(permits as usize).await,\n                }\n            } else if #[cfg(feature = \"_rt-tokio\")] {\n                AsyncSemaphoreReleaser {\n                    inner: self\n                        .inner\n                        // Weird quirk: `tokio::sync::Semaphore` mostly uses `usize` for permit counts,\n                        // but `u32` for this and `try_acquire_many()`.\n                        .acquire_many(permits)\n                        .await\n                        .expect(\"BUG: we do not expose the `.close()` method\"),\n                }\n            } else {\n                crate::rt::missing_rt(permits)\n            }\n        }\n    }\n\n    pub fn try_acquire(&self, permits: u32) -> Option<AsyncSemaphoreReleaser<'_>> {\n        cfg_if! {\n            if #[cfg(all(\n                any(\n                    feature = \"_rt-async-global-executor\",\n                    feature = \"_rt-async-std\",\n                    feature = \"_rt-smol\"\n                ),\n                not(feature = \"_rt-tokio\")\n            ))] {\n                Some(AsyncSemaphoreReleaser {\n                    inner: self.inner.try_acquire(permits as usize)?,\n                })\n            } else if #[cfg(feature = \"_rt-tokio\")] {\n                Some(AsyncSemaphoreReleaser {\n                    inner: self.inner.try_acquire_many(permits).ok()?,\n                })\n            } else {\n                crate::rt::missing_rt(permits)\n            }\n        }\n    }\n\n    pub fn release(&self, permits: usize) {\n        cfg_if! {\n            if #[cfg(all(\n                any(\n                    feature = \"_rt-async-global-executor\",\n                    feature = \"_rt-async-std\",\n                    feature = \"_rt-smol\"\n                ),\n                not(feature = \"_rt-tokio\")\n            ))] {\n                self.inner.release(permits);\n            } else if #[cfg(feature = \"_rt-tokio\")] {\n                self.inner.add_permits(permits);\n            } else {\n                crate::rt::missing_rt(permits);\n            }\n        }\n    }\n}\n\npub struct AsyncSemaphoreReleaser<'a> {\n    // We use the semaphore from futures-intrusive as the one from async-std\n    // is missing the ability to add arbitrary permits, and is not guaranteed to be fair:\n    // * https://github.com/smol-rs/async-lock/issues/22\n    // * https://github.com/smol-rs/async-lock/issues/23\n    //\n    // We're on the look-out for a replacement, however, as futures-intrusive is not maintained\n    // and there are some soundness concerns (although it turns out any intrusive future is unsound\n    // in MIRI due to the necessitated mutable aliasing):\n    // https://github.com/launchbadge/sqlx/issues/1668\n    #[cfg(all(\n        any(\n            feature = \"_rt-async-global-executor\",\n            feature = \"_rt-async-std\",\n            feature = \"_rt-smol\"\n        ),\n        not(feature = \"_rt-tokio\")\n    ))]\n    inner: futures_intrusive::sync::SemaphoreReleaser<'a>,\n\n    #[cfg(feature = \"_rt-tokio\")]\n    inner: tokio::sync::SemaphorePermit<'a>,\n\n    #[cfg(not(any(\n        feature = \"_rt-async-global-executor\",\n        feature = \"_rt-async-std\",\n        feature = \"_rt-smol\",\n        feature = \"_rt-tokio\"\n    )))]\n    _phantom: std::marker::PhantomData<&'a ()>,\n}\n\nimpl AsyncSemaphoreReleaser<'_> {\n    pub fn disarm(self) {\n        cfg_if! {\n            if #[cfg(all(\n                any(\n                    feature = \"_rt-async-global-executor\",\n                    feature = \"_rt-async-std\",\n                    feature = \"_rt-smol\"\n                ),\n                not(feature = \"_rt-tokio\")\n            ))] {\n                let mut this = self;\n                this.inner.disarm();\n            } else if #[cfg(feature = \"_rt-tokio\")] {\n                self.inner.forget();\n            } else {\n                crate::rt::missing_rt(());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/testing/fixtures.rs",
    "content": "//! TODO: automatic test fixture capture\n\nuse crate::database::Database;\n\nuse crate::query_builder::QueryBuilder;\n\nuse indexmap::set::IndexSet;\nuse std::cmp;\nuse std::collections::{BTreeMap, HashMap};\nuse std::marker::PhantomData;\nuse std::sync::Arc;\n\npub type Result<T, E = FixtureError> = std::result::Result<T, E>;\n\n/// A snapshot of the current state of the database.\n///\n/// Can be used to generate an `INSERT` fixture for populating an empty database,\n/// or in the future it may be possible to generate a fixture from the difference between\n/// two snapshots.\npub struct FixtureSnapshot<DB> {\n    tables: BTreeMap<TableName, Table>,\n    db: PhantomData<DB>,\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"could not create fixture: {0}\")]\npub struct FixtureError(String);\n\npub struct Fixture<DB> {\n    ops: Vec<FixtureOp>,\n    db: PhantomData<DB>,\n}\n\nenum FixtureOp {\n    Insert {\n        table: TableName,\n        columns: Vec<ColumnName>,\n        rows: Vec<Vec<Value>>,\n    },\n    // TODO: handle updates and deletes by diffing two snapshots\n}\n\ntype TableName = Arc<str>;\ntype ColumnName = Arc<str>;\ntype Value = String;\n\nstruct Table {\n    name: TableName,\n    columns: IndexSet<ColumnName>,\n    rows: Vec<Vec<Value>>,\n    foreign_keys: HashMap<ColumnName, (TableName, ColumnName)>,\n}\n\nmacro_rules! fixture_assert (\n    ($cond:expr, $msg:literal $($arg:tt)*) => {\n        if !($cond) {\n            return Err(FixtureError(format!($msg $($arg)*)))\n        }\n    }\n);\n\nimpl<DB: Database> FixtureSnapshot<DB> {\n    /// Generate a fixture to reproduce this snapshot from an empty database using `INSERT`s.\n    ///\n    /// Note that this doesn't take into account any triggers that might modify the data before\n    /// it's stored.\n    ///\n    /// The `INSERT` statements are ordered on a best-effort basis to satisfy any foreign key\n    /// constraints (data from tables with no foreign keys are inserted first, then the tables\n    /// that reference those tables, and so on).\n    ///\n    /// If a cycle in foreign-key constraints is detected, this returns with an error.\n    pub fn additive_fixture(&self) -> Result<Fixture<DB>> {\n        let visit_order = self.calculate_visit_order()?;\n\n        let mut ops = Vec::new();\n\n        for table_name in visit_order {\n            let table = self.tables.get(&table_name).unwrap();\n\n            ops.push(FixtureOp::Insert {\n                table: table_name,\n                columns: table.columns.iter().cloned().collect(),\n                rows: table.rows.clone(),\n            });\n        }\n\n        Ok(Fixture { ops, db: self.db })\n    }\n\n    /// Determine an order for outputting `INSERTS` for each table by calculating the max\n    /// length of all its foreign key chains.\n    ///\n    /// This should hopefully ensure that there are no foreign-key errors.\n    fn calculate_visit_order(&self) -> Result<Vec<TableName>> {\n        let mut table_depths = HashMap::with_capacity(self.tables.len());\n        let mut visited_set = IndexSet::with_capacity(self.tables.len());\n\n        for table in self.tables.values() {\n            foreign_key_depth(&self.tables, table, &mut table_depths, &mut visited_set)?;\n            visited_set.clear();\n        }\n\n        let mut table_names: Vec<TableName> = table_depths.keys().cloned().collect();\n        table_names.sort_by_key(|name| table_depths.get(name).unwrap());\n        Ok(table_names)\n    }\n}\n\n/// Implements `ToString` but not `Display` because it uses [`QueryBuilder`] internally,\n/// which appends to an internal string.\n#[allow(clippy::to_string_trait_impl)]\nimpl<DB: Database> ToString for Fixture<DB>\nwhere\n    for<'a> <DB as Database>::Arguments: Default,\n{\n    fn to_string(&self) -> String {\n        let mut query = QueryBuilder::<DB>::new(\"\");\n\n        for op in &self.ops {\n            match op {\n                FixtureOp::Insert {\n                    table,\n                    columns,\n                    rows,\n                } => {\n                    // Sanity check, empty tables shouldn't appear in snapshots anyway.\n                    if columns.is_empty() || rows.is_empty() {\n                        continue;\n                    }\n\n                    query.push(format_args!(\"INSERT INTO {table} (\"));\n\n                    let mut separated = query.separated(\", \");\n\n                    for column in columns {\n                        separated.push(column);\n                    }\n\n                    query.push(\")\\n\");\n\n                    query.push_values(rows, |mut separated, row| {\n                        for value in row {\n                            separated.push(value);\n                        }\n                    });\n\n                    query.push(\";\\n\");\n                }\n            }\n        }\n\n        query.into_string()\n    }\n}\n\nfn foreign_key_depth(\n    tables: &BTreeMap<TableName, Table>,\n    table: &Table,\n    depths: &mut HashMap<TableName, usize>,\n    visited_set: &mut IndexSet<TableName>,\n) -> Result<usize> {\n    if let Some(&depth) = depths.get(&table.name) {\n        return Ok(depth);\n    }\n\n    // This keeps us from looping forever.\n    fixture_assert!(\n        visited_set.insert(table.name.clone()),\n        \"foreign key cycle detected: {:?} -> {:?}\",\n        visited_set,\n        table.name\n    );\n\n    let mut refdepth = 0;\n\n    for (colname, (refname, refcol)) in &table.foreign_keys {\n        let referenced = tables.get(refname).ok_or_else(|| {\n            FixtureError(format!(\n                \"table {:?} in foreign key `{}.{} references {}.{}` does not exist\",\n                refname, table.name, colname, refname, refcol\n            ))\n        })?;\n\n        refdepth = cmp::max(\n            refdepth,\n            foreign_key_depth(tables, referenced, depths, visited_set)?,\n        );\n    }\n\n    let depth = refdepth + 1;\n\n    depths.insert(table.name.clone(), depth);\n\n    Ok(depth)\n}\n\n#[test]\n#[cfg(feature = \"any\")]\nfn test_additive_fixture() -> Result<()> {\n    // Just need something that implements `Database`\n    use crate::any::Any;\n\n    let mut snapshot = FixtureSnapshot {\n        tables: BTreeMap::new(),\n        db: PhantomData::<Any>,\n    };\n\n    snapshot.tables.insert(\n        \"foo\".into(),\n        Table {\n            name: \"foo\".into(),\n            columns: [\"foo_id\", \"foo_a\", \"foo_b\"]\n                .into_iter()\n                .map(Arc::<str>::from)\n                .collect(),\n            rows: vec![vec![\"1\".into(), \"'asdf'\".into(), \"true\".into()]],\n            foreign_keys: HashMap::new(),\n        },\n    );\n\n    // foreign-keyed to `foo`\n    // since `tables` is a `BTreeMap` we would expect a naive algorithm to visit this first.\n    snapshot.tables.insert(\n        \"bar\".into(),\n        Table {\n            name: \"bar\".into(),\n            columns: [\"bar_id\", \"foo_id\", \"bar_a\", \"bar_b\"]\n                .into_iter()\n                .map(Arc::<str>::from)\n                .collect(),\n            rows: vec![vec![\n                \"1234\".into(),\n                \"1\".into(),\n                \"'2022-07-22 23:27:48.775113301+00:00'\".into(),\n                \"3.14\".into(),\n            ]],\n            foreign_keys: [(\"foo_id\".into(), (\"foo\".into(), \"foo_id\".into()))]\n                .into_iter()\n                .collect(),\n        },\n    );\n\n    // foreign-keyed to both `foo` and `bar`\n    snapshot.tables.insert(\n        \"baz\".into(),\n        Table {\n            name: \"baz\".into(),\n            columns: [\"baz_id\", \"bar_id\", \"foo_id\", \"baz_a\", \"baz_b\"]\n                .into_iter()\n                .map(Arc::<str>::from)\n                .collect(),\n            rows: vec![vec![\n                \"5678\".into(),\n                \"1234\".into(),\n                \"1\".into(),\n                \"'2022-07-22 23:27:48.775113301+00:00'\".into(),\n                \"3.14\".into(),\n            ]],\n            foreign_keys: [\n                (\"foo_id\".into(), (\"foo\".into(), \"foo_id\".into())),\n                (\"bar_id\".into(), (\"bar\".into(), \"bar_id\".into())),\n            ]\n            .into_iter()\n            .collect(),\n        },\n    );\n\n    let fixture = snapshot.additive_fixture()?;\n\n    assert_eq!(\n        fixture.to_string(),\n        \"INSERT INTO foo (foo_id, foo_a, foo_b)\\n\\\n         VALUES (1, 'asdf', true);\\n\\\n         INSERT INTO bar (bar_id, foo_id, bar_a, bar_b)\\n\\\n         VALUES (1234, 1, '2022-07-22 23:27:48.775113301+00:00', 3.14);\\n\\\n         INSERT INTO baz (baz_id, bar_id, foo_id, baz_a, baz_b)\\n\\\n         VALUES (5678, 1234, 1, '2022-07-22 23:27:48.775113301+00:00', 3.14);\\n\"\n    );\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-core/src/testing/mod.rs",
    "content": "use std::future::Future;\nuse std::time::Duration;\n\nuse base64::{engine::general_purpose::URL_SAFE, Engine as _};\npub use fixtures::FixtureSnapshot;\nuse sha2::{Digest, Sha512};\n\nuse crate::connection::{ConnectOptions, Connection};\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::migrate::{Migrate, Migrator};\nuse crate::pool::{Pool, PoolConnection, PoolOptions};\n\nmod fixtures;\n\npub trait TestSupport: Database {\n    /// Get parameters to construct a `Pool` suitable for testing.\n    ///\n    /// This `Pool` instance will behave somewhat specially:\n    /// * all handles share a single global semaphore to avoid exceeding the connection limit\n    ///   on the database server.\n    /// * each invocation results in a different temporary database.\n    ///\n    /// The implementation may require `DATABASE_URL` to be set in order to manage databases.\n    /// The user credentials it contains must have the privilege to create and drop databases.\n    fn test_context(\n        args: &TestArgs,\n    ) -> impl Future<Output = Result<TestContext<Self>, Error>> + Send + '_;\n\n    fn cleanup_test(db_name: &str) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    /// Cleanup any test databases that are no longer in-use.\n    ///\n    /// Returns a count of the databases deleted, if possible.\n    ///\n    /// The implementation may require `DATABASE_URL` to be set in order to manage databases.\n    /// The user credentials it contains must have the privilege to create and drop databases.\n    fn cleanup_test_dbs() -> impl Future<Output = Result<Option<usize>, Error>> + Send + 'static;\n\n    /// Take a snapshot of the current state of the database (data only).\n    ///\n    /// This snapshot can then be used to generate test fixtures.\n    fn snapshot(\n        conn: &mut Self::Connection,\n    ) -> impl Future<Output = Result<FixtureSnapshot<Self>, Error>> + Send + '_;\n\n    /// Generate a unique database name for the given test path.\n    fn db_name(args: &TestArgs) -> String {\n        let mut hasher = Sha512::new();\n        hasher.update(args.test_path.as_bytes());\n        let hash = hasher.finalize();\n        let hash = URL_SAFE.encode(&hash[..39]);\n        let db_name = format!(\"_sqlx_test_{}\", hash).replace('-', \"_\");\n        debug_assert!(db_name.len() == 63);\n        db_name\n    }\n}\n\npub struct TestFixture {\n    pub path: &'static str,\n    pub contents: &'static str,\n}\n\npub struct TestArgs {\n    pub test_path: &'static str,\n    pub migrator: Option<&'static Migrator>,\n    pub fixtures: &'static [TestFixture],\n}\n\npub trait TestFn {\n    type Output;\n\n    fn run_test(self, args: TestArgs) -> Self::Output;\n}\n\npub trait TestTermination {\n    fn is_success(&self) -> bool;\n}\n\npub struct TestContext<DB: Database> {\n    pub pool_opts: PoolOptions<DB>,\n    pub connect_opts: <DB::Connection as Connection>::Options,\n    pub db_name: String,\n}\n\nimpl<DB, Fut> TestFn for fn(Pool<DB>) -> Fut\nwhere\n    DB: TestSupport + Database,\n    DB::Connection: Migrate,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n    Fut: Future,\n    Fut::Output: TestTermination,\n{\n    type Output = Fut::Output;\n\n    fn run_test(self, args: TestArgs) -> Self::Output {\n        run_test_with_pool(args, self)\n    }\n}\n\nimpl<DB, Fut> TestFn for fn(PoolConnection<DB>) -> Fut\nwhere\n    DB: TestSupport + Database,\n    DB::Connection: Migrate,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n    Fut: Future,\n    Fut::Output: TestTermination,\n{\n    type Output = Fut::Output;\n\n    fn run_test(self, args: TestArgs) -> Self::Output {\n        run_test_with_pool(args, |pool| async move {\n            let conn = pool\n                .acquire()\n                .await\n                .expect(\"failed to acquire test pool connection\");\n            let res = (self)(conn).await;\n            pool.close().await;\n            res\n        })\n    }\n}\n\nimpl<DB, Fut> TestFn for fn(PoolOptions<DB>, <DB::Connection as Connection>::Options) -> Fut\nwhere\n    DB: Database + TestSupport,\n    DB::Connection: Migrate,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n    Fut: Future,\n    Fut::Output: TestTermination,\n{\n    type Output = Fut::Output;\n\n    fn run_test(self, args: TestArgs) -> Self::Output {\n        run_test(args, self)\n    }\n}\n\nimpl<Fut> TestFn for fn() -> Fut\nwhere\n    Fut: Future,\n{\n    type Output = Fut::Output;\n\n    fn run_test(self, args: TestArgs) -> Self::Output {\n        assert!(\n            args.fixtures.is_empty(),\n            \"fixtures cannot be applied for a bare function\"\n        );\n        crate::rt::test_block_on(self())\n    }\n}\n\nimpl TestArgs {\n    pub fn new(test_path: &'static str) -> Self {\n        TestArgs {\n            test_path,\n            migrator: None,\n            fixtures: &[],\n        }\n    }\n\n    pub fn migrator(&mut self, migrator: &'static Migrator) {\n        self.migrator = Some(migrator);\n    }\n\n    pub fn fixtures(&mut self, fixtures: &'static [TestFixture]) {\n        self.fixtures = fixtures;\n    }\n}\n\nimpl TestTermination for () {\n    fn is_success(&self) -> bool {\n        true\n    }\n}\n\nimpl<T, E> TestTermination for Result<T, E> {\n    fn is_success(&self) -> bool {\n        self.is_ok()\n    }\n}\n\nfn run_test_with_pool<DB, F, Fut>(args: TestArgs, test_fn: F) -> Fut::Output\nwhere\n    DB: TestSupport,\n    DB::Connection: Migrate,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n    F: FnOnce(Pool<DB>) -> Fut,\n    Fut: Future,\n    Fut::Output: TestTermination,\n{\n    let test_path = args.test_path;\n    run_test::<DB, _, _>(args, |pool_opts, connect_opts| async move {\n        let pool = pool_opts\n            .connect_with(connect_opts)\n            .await\n            .expect(\"failed to connect test pool\");\n\n        let res = test_fn(pool.clone()).await;\n\n        let close_timed_out = crate::rt::timeout(Duration::from_secs(10), pool.close())\n            .await\n            .is_err();\n\n        if close_timed_out {\n            eprintln!(\"test {test_path} held onto Pool after exiting\");\n        }\n\n        res\n    })\n}\n\nfn run_test<DB, F, Fut>(args: TestArgs, test_fn: F) -> Fut::Output\nwhere\n    DB: TestSupport,\n    DB::Connection: Migrate,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n    F: FnOnce(PoolOptions<DB>, <DB::Connection as Connection>::Options) -> Fut,\n    Fut: Future,\n    Fut::Output: TestTermination,\n{\n    crate::rt::test_block_on(async move {\n        let test_context = DB::test_context(&args)\n            .await\n            .expect(\"failed to connect to setup test database\");\n\n        setup_test_db::<DB>(&test_context.connect_opts, &args).await;\n\n        let res = test_fn(test_context.pool_opts, test_context.connect_opts).await;\n\n        if res.is_success() {\n            if let Err(e) = DB::cleanup_test(&DB::db_name(&args)).await {\n                eprintln!(\n                    \"failed to delete database {:?}: {}\",\n                    test_context.db_name, e\n                );\n            }\n        }\n\n        res\n    })\n}\n\nasync fn setup_test_db<DB: Database>(\n    copts: &<DB::Connection as Connection>::Options,\n    args: &TestArgs,\n) where\n    DB::Connection: Migrate + Sized,\n    for<'c> &'c mut DB::Connection: Executor<'c, Database = DB>,\n{\n    let mut conn = copts\n        .connect()\n        .await\n        .expect(\"failed to connect to test database\");\n\n    if let Some(migrator) = args.migrator {\n        migrator\n            .run_direct(None, &mut conn)\n            .await\n            .expect(\"failed to apply migrations\");\n    }\n\n    for fixture in args.fixtures {\n        (&mut conn)\n            .execute(fixture.contents)\n            .await\n            .unwrap_or_else(|e| panic!(\"failed to apply test fixture {:?}: {:?}\", fixture.path, e));\n    }\n\n    conn.close()\n        .await\n        .expect(\"failed to close setup connection\");\n}\n"
  },
  {
    "path": "sqlx-core/src/transaction.rs",
    "content": "use std::fmt::{self, Debug, Formatter};\nuse std::future::{self, Future};\nuse std::ops::{Deref, DerefMut};\n\nuse futures_core::future::BoxFuture;\n\nuse crate::database::Database;\nuse crate::error::Error;\nuse crate::pool::MaybePoolConnection;\nuse crate::sql_str::{AssertSqlSafe, SqlSafeStr, SqlStr};\n\n/// Generic management of database transactions.\n///\n/// This trait should not be used, except when implementing [`Connection`].\npub trait TransactionManager {\n    type Database: Database;\n\n    /// Begin a new transaction or establish a savepoint within the active transaction.\n    ///\n    /// If this is a new transaction, `statement` may be used instead of the\n    /// default \"BEGIN\" statement.\n    ///\n    /// If we are already inside a transaction and `statement.is_some()`, then\n    /// `Error::InvalidSavePoint` is returned without running any statements.\n    fn begin(\n        conn: &mut <Self::Database as Database>::Connection,\n        statement: Option<SqlStr>,\n    ) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    /// Commit the active transaction or release the most recent savepoint.\n    fn commit(\n        conn: &mut <Self::Database as Database>::Connection,\n    ) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    /// Abort the active transaction or restore from the most recent savepoint.\n    fn rollback(\n        conn: &mut <Self::Database as Database>::Connection,\n    ) -> impl Future<Output = Result<(), Error>> + Send + '_;\n\n    /// Starts to abort the active transaction or restore from the most recent snapshot.\n    fn start_rollback(conn: &mut <Self::Database as Database>::Connection);\n\n    /// Returns the current transaction depth.\n    ///\n    /// Transaction depth indicates the level of nested transactions:\n    /// - Level 0: No active transaction.\n    /// - Level 1: A transaction is active.\n    /// - Level 2 or higher: A transaction is active and one or more SAVEPOINTs have been created within it.\n    fn get_transaction_depth(conn: &<Self::Database as Database>::Connection) -> usize;\n}\n\n/// An in-progress database transaction or savepoint.\n///\n/// A transaction starts with a call to [`Pool::begin`] or [`Connection::begin`].\n///\n/// A transaction should end with a call to [`commit`] or [`rollback`]. If neither are called\n/// before the transaction goes out-of-scope, [`rollback`] is called. In other\n/// words, [`rollback`] is called on `drop` if the transaction is still in-progress.\n///\n/// A savepoint is a special mark inside a transaction that allows all commands that are\n/// executed after it was established to be rolled back, restoring the transaction state to\n/// what it was at the time of the savepoint.\n///\n/// A transaction can be used as an [`Executor`] when performing queries:\n/// ```rust,no_run\n/// # use sqlx_core::acquire::Acquire;\n/// # async fn example() -> sqlx::Result<()> {\n/// # let id = 1;\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// let mut tx = conn.begin().await?;\n///\n/// let result = sqlx::query(\"DELETE FROM \\\"testcases\\\" WHERE id = $1\")\n///     .bind(id)\n///     .execute(&mut *tx)\n///     .await?\n///     .rows_affected();\n///\n/// tx.commit().await\n/// # }\n/// ```\n/// [`Executor`]: crate::executor::Executor\n/// [`Connection::begin`]: crate::connection::Connection::begin()\n/// [`Pool::begin`]: crate::pool::Pool::begin()\n/// [`commit`]: Self::commit()\n/// [`rollback`]: Self::rollback()\npub struct Transaction<'c, DB>\nwhere\n    DB: Database,\n{\n    connection: MaybePoolConnection<'c, DB>,\n    open: bool,\n}\n\nimpl<'c, DB> Transaction<'c, DB>\nwhere\n    DB: Database,\n{\n    #[doc(hidden)]\n    pub fn begin(\n        conn: impl Into<MaybePoolConnection<'c, DB>>,\n        statement: Option<SqlStr>,\n    ) -> BoxFuture<'c, Result<Self, Error>> {\n        let conn = conn.into();\n\n        Box::pin(async move {\n            let mut tx = Self {\n                connection: conn,\n\n                // If the call to `begin` fails or doesn't complete we want to attempt a rollback in case the transaction was started.\n                open: true,\n            };\n\n            DB::TransactionManager::begin(&mut tx.connection, statement).await?;\n\n            Ok(tx)\n        })\n    }\n\n    /// Commits this transaction or savepoint.\n    pub async fn commit(mut self) -> Result<(), Error> {\n        DB::TransactionManager::commit(&mut self.connection).await?;\n        self.open = false;\n\n        Ok(())\n    }\n\n    /// Aborts this transaction or savepoint.\n    pub async fn rollback(mut self) -> Result<(), Error> {\n        DB::TransactionManager::rollback(&mut self.connection).await?;\n        self.open = false;\n\n        Ok(())\n    }\n}\n\n// NOTE: fails to compile due to lack of lazy normalization\n// impl<'c, 't, DB: Database> crate::executor::Executor<'t>\n//     for &'t mut crate::transaction::Transaction<'c, DB>\n// where\n//     &'c mut DB::Connection: Executor<'c, Database = DB>,\n// {\n//     type Database = DB;\n//\n//\n//\n//     fn fetch_many<'e, 'q: 'e, E: 'q>(\n//         self,\n//         query: E,\n//     ) -> futures_core::stream::BoxStream<\n//         'e,\n//         Result<\n//             crate::Either<<DB as crate::database::Database>::QueryResult, DB::Row>,\n//             crate::error::Error,\n//         >,\n//     >\n//     where\n//         't: 'e,\n//         E: crate::executor::Execute<'q, Self::Database>,\n//     {\n//         (&mut **self).fetch_many(query)\n//     }\n//\n//     fn fetch_optional<'e, 'q: 'e, E: 'q>(\n//         self,\n//         query: E,\n//     ) -> futures_core::future::BoxFuture<'e, Result<Option<DB::Row>, crate::error::Error>>\n//     where\n//         't: 'e,\n//         E: crate::executor::Execute<'q, Self::Database>,\n//     {\n//         (&mut **self).fetch_optional(query)\n//     }\n//\n//     fn prepare_with<'e, 'q: 'e>(\n//         self,\n//         sql: &'q str,\n//         parameters: &'e [<Self::Database as crate::database::Database>::TypeInfo],\n//     ) -> futures_core::future::BoxFuture<\n//         'e,\n//         Result<\n//             <Self::Database as crate::database::Database>::Statement<'q>,\n//             crate::error::Error,\n//         >,\n//     >\n//     where\n//         't: 'e,\n//     {\n//         (&mut **self).prepare_with(sql, parameters)\n//     }\n//\n//     #[doc(hidden)]\n//     #[cfg(feature = \"offline\")]\n//     fn describe<'e, 'q: 'e>(\n//         self,\n//         query: &'q str,\n//     ) -> futures_core::future::BoxFuture<\n//         'e,\n//         Result<crate::describe::Describe<Self::Database>, crate::error::Error>,\n//     >\n//     where\n//         't: 'e,\n//     {\n//         (&mut **self).describe(query)\n//     }\n// }\n\nimpl<DB> Debug for Transaction<'_, DB>\nwhere\n    DB: Database,\n{\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        // TODO: Show the full type <..<..<..\n        f.debug_struct(\"Transaction\").finish()\n    }\n}\n\nimpl<DB> Deref for Transaction<'_, DB>\nwhere\n    DB: Database,\n{\n    type Target = DB::Connection;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        &self.connection\n    }\n}\n\nimpl<DB> DerefMut for Transaction<'_, DB>\nwhere\n    DB: Database,\n{\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.connection\n    }\n}\n\n// Implement `AsMut<DB::Connection>` so `Transaction` can be given to a\n// `PgAdvisoryLockGuard`.\n//\n// See: https://github.com/launchbadge/sqlx/issues/2520\nimpl<DB: Database> AsMut<DB::Connection> for Transaction<'_, DB> {\n    fn as_mut(&mut self) -> &mut DB::Connection {\n        &mut self.connection\n    }\n}\n\nimpl<'t, DB: Database> crate::acquire::Acquire<'t> for &'t mut Transaction<'_, DB> {\n    type Database = DB;\n\n    type Connection = &'t mut <DB as Database>::Connection;\n\n    #[inline]\n    fn acquire(self) -> BoxFuture<'t, Result<Self::Connection, Error>> {\n        Box::pin(future::ready(Ok(&mut **self)))\n    }\n\n    #[inline]\n    fn begin(self) -> BoxFuture<'t, Result<Transaction<'t, DB>, Error>> {\n        Transaction::begin(&mut **self, None)\n    }\n}\n\nimpl<DB> Drop for Transaction<'_, DB>\nwhere\n    DB: Database,\n{\n    fn drop(&mut self) {\n        if self.open {\n            // starts a rollback operation\n\n            // what this does depends on the database but generally this means we queue a rollback\n            // operation that will happen on the next asynchronous invocation of the underlying\n            // connection (including if the connection is returned to a pool)\n\n            DB::TransactionManager::start_rollback(&mut self.connection);\n        }\n    }\n}\n\npub fn begin_ansi_transaction_sql(depth: usize) -> SqlStr {\n    if depth == 0 {\n        \"BEGIN\".into_sql_str()\n    } else {\n        AssertSqlSafe(format!(\"SAVEPOINT _sqlx_savepoint_{depth}\")).into_sql_str()\n    }\n}\n\npub fn commit_ansi_transaction_sql(depth: usize) -> SqlStr {\n    if depth == 1 {\n        \"COMMIT\".into_sql_str()\n    } else {\n        AssertSqlSafe(format!(\"RELEASE SAVEPOINT _sqlx_savepoint_{}\", depth - 1)).into_sql_str()\n    }\n}\n\npub fn rollback_ansi_transaction_sql(depth: usize) -> SqlStr {\n    if depth == 1 {\n        \"ROLLBACK\".into_sql_str()\n    } else {\n        AssertSqlSafe(format!(\n            \"ROLLBACK TO SAVEPOINT _sqlx_savepoint_{}\",\n            depth - 1\n        ))\n        .into_sql_str()\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/type_checking.rs",
    "content": "use crate::config::macros::PreferredCrates;\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::type_info::TypeInfo;\nuse crate::value::Value;\nuse std::any::Any;\nuse std::fmt;\nuse std::fmt::{Debug, Formatter};\n\n/// The type of query parameter checking done by a SQL database.\n#[derive(PartialEq, Eq)]\npub enum ParamChecking {\n    /// Parameter checking is weak or nonexistent (uses coercion or allows mismatches).\n    Weak,\n    /// Parameter checking is strong (types must match exactly).\n    Strong,\n}\n\n/// Type-checking extensions for the `Database` trait.\n///\n/// Mostly supporting code for the macros, and for `Debug` impls.\npub trait TypeChecking: Database {\n    /// Describes how the database in question typechecks query parameters.\n    const PARAM_CHECKING: ParamChecking;\n\n    /// Get the full path of the Rust type that corresponds to the given `TypeInfo`, if applicable.\n    ///\n    /// If the type has a borrowed equivalent suitable for query parameters,\n    /// this is that borrowed type.\n    fn param_type_for_id(\n        id: &Self::TypeInfo,\n        preferred_crates: &PreferredCrates,\n    ) -> Result<&'static str, Error>;\n\n    /// Get the full path of the Rust type that corresponds to the given `TypeInfo`, if applicable.\n    ///\n    /// Always returns the owned version of the type, suitable for decoding from `Row`.\n    fn return_type_for_id(\n        id: &Self::TypeInfo,\n        preferred_crates: &PreferredCrates,\n    ) -> Result<&'static str, Error>;\n\n    /// Get the name of the Cargo feature gate that must be enabled to process the given `TypeInfo`,\n    /// if applicable.\n    fn get_feature_gate(info: &Self::TypeInfo) -> Option<&'static str>;\n\n    /// If `value` is a well-known type, decode and format it using `Debug`.\n    ///\n    /// If `value` is not a well-known type or could not be decoded, the reason is printed instead.\n    fn fmt_value_debug(value: &<Self as Database>::Value) -> FmtValue<'_, Self>;\n}\n\npub type Result<T, E = Error> = std::result::Result<T, E>;\n\n#[derive(Debug, thiserror::Error)]\npub enum Error {\n    #[error(\"no built-in mapping found for SQL type; a type override may be required\")]\n    NoMappingFound,\n    #[error(\"Cargo feature for configured `macros.preferred-crates.date-time` not enabled\")]\n    DateTimeCrateFeatureNotEnabled,\n    #[error(\"Cargo feature for configured `macros.preferred-crates.numeric` not enabled\")]\n    NumericCrateFeatureNotEnabled,\n    #[error(\"multiple date-time types are possible; falling back to `{fallback}`\")]\n    AmbiguousDateTimeType { fallback: &'static str },\n    #[error(\"multiple numeric types are possible; falling back to `{fallback}`\")]\n    AmbiguousNumericType { fallback: &'static str },\n}\n\n/// An adapter for [`Value`] which attempts to decode the value and format it when printed using [`Debug`].\npub struct FmtValue<'v, DB>\nwhere\n    DB: Database,\n{\n    value: &'v <DB as Database>::Value,\n    fmt: fn(&'v <DB as Database>::Value, &mut Formatter<'_>) -> fmt::Result,\n}\n\nimpl<'v, DB> FmtValue<'v, DB>\nwhere\n    DB: Database,\n{\n    // This API can't take `ValueRef` directly as it would need to pass it to `Decode` by-value,\n    // which means taking ownership of it. We cannot rely on a `Clone` impl because `SqliteValueRef` doesn't have one.\n    /// When printed with [`Debug`], attempt to decode `value` as the given type `T` and format it using [`Debug`].\n    ///\n    /// If `value` could not be decoded as `T`, the reason is printed instead.\n    pub fn debug<T>(value: &'v <DB as Database>::Value) -> Self\n    where\n        T: Decode<'v, DB> + Debug + Any,\n    {\n        Self {\n            value,\n            fmt: |value, f| {\n                let info = value.type_info();\n\n                match T::decode(value.as_ref()) {\n                    Ok(value) => Debug::fmt(&value, f),\n                    Err(e) => {\n                        if e.is::<crate::error::UnexpectedNullError>() {\n                            f.write_str(\"NULL\")\n                        } else {\n                            f.write_fmt(format_args!(\n                                \"(error decoding SQL type {} as {}: {e:?})\",\n                                info.name(),\n                                std::any::type_name::<T>()\n                            ))\n                        }\n                    }\n                }\n            },\n        }\n    }\n\n    /// If the type to be decoded is not known or not supported, print the SQL type instead,\n    /// as well as any applicable SQLx feature that needs to be enabled.\n    pub fn unknown(value: &'v <DB as Database>::Value) -> Self\n    where\n        DB: TypeChecking,\n    {\n        Self {\n            value,\n            fmt: |value, f| {\n                let info = value.type_info();\n\n                if let Some(feature_gate) = <DB as TypeChecking>::get_feature_gate(&info) {\n                    return f.write_fmt(format_args!(\n                        \"(unknown SQL type {}: SQLx feature {feature_gate} not enabled)\",\n                        info.name()\n                    ));\n                }\n\n                f.write_fmt(format_args!(\"(unknown SQL type {})\", info.name()))\n            },\n        }\n    }\n}\n\nimpl<DB> Debug for FmtValue<'_, DB>\nwhere\n    DB: Database,\n{\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        (self.fmt)(self.value, f)\n    }\n}\n\n#[doc(hidden)]\n#[macro_export]\nmacro_rules! select_input_type {\n    ($ty:ty, $input:ty) => {\n        stringify!($input)\n    };\n    ($ty:ty) => {\n        stringify!($ty)\n    };\n}\n\n#[macro_export]\nmacro_rules! impl_type_checking {\n    (\n        $database:path {\n            $($(#[$meta:meta])? $ty:ty $(| $input:ty)?),*$(,)?\n        },\n        ParamChecking::$param_checking:ident,\n        feature-types: $ty_info:ident => $get_gate:expr,\n        datetime-types: {\n            chrono: {\n                $($chrono_ty:ty $(| $chrono_input:ty)?),*$(,)?\n            },\n            time: {\n                $($time_ty:ty $(| $time_input:ty)?),*$(,)?\n            },\n        },\n        numeric-types: {\n            bigdecimal: {\n                $($bigdecimal_ty:ty $(| $bigdecimal_input:ty)?),*$(,)?\n            },\n            rust_decimal: {\n                $($rust_decimal_ty:ty $(| $rust_decimal_input:ty)?),*$(,)?\n            },\n        },\n    ) => {\n        impl $crate::type_checking::TypeChecking for $database {\n            const PARAM_CHECKING: $crate::type_checking::ParamChecking = $crate::type_checking::ParamChecking::$param_checking;\n\n            fn param_type_for_id(\n                info: &Self::TypeInfo,\n                preferred_crates: &$crate::config::macros::PreferredCrates,\n            ) -> Result<&'static str, $crate::type_checking::Error> {\n                use $crate::config::macros::{DateTimeCrate, NumericCrate};\n                use $crate::type_checking::Error;\n\n                // Check non-special types\n                // ---------------------\n                $(\n                    $(#[$meta])?\n                    if <$ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                        return Ok($crate::select_input_type!($ty $(, $input)?));\n                    }\n                )*\n\n                $(\n                    $(#[$meta])?\n                    if <$ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                        return Ok($crate::select_input_type!($ty $(, $input)?));\n                    }\n                )*\n\n                // Check `macros.preferred-crates.date-time`\n                //\n                // Due to legacy reasons, `time` takes precedent over `chrono` if both are enabled.\n                // Any crates added later should be _lower_ priority than `chrono` to avoid breakages.\n                // ----------------------------------------\n                #[cfg(feature = \"time\")]\n                if matches!(preferred_crates.date_time, DateTimeCrate::Time | DateTimeCrate::Inferred) {\n                    $(\n                        if <$time_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            if cfg!(feature = \"chrono\") {\n                                return Err($crate::type_checking::Error::AmbiguousDateTimeType {\n                                    fallback: $crate::select_input_type!($time_ty $(, $time_input)?),\n                                });\n                            }\n\n                            return Ok($crate::select_input_type!($time_ty $(, $time_input)?));\n                        }\n                    )*\n\n                    $(\n                        if <$time_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            if cfg!(feature = \"chrono\") {\n                                return Err($crate::type_checking::Error::AmbiguousDateTimeType {\n                                    fallback: $crate::select_input_type!($time_ty $(, $time_input)?),\n                                });\n                            }\n\n                            return Ok($crate::select_input_type!($time_ty $(, $time_input)?));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"time\"))]\n                if preferred_crates.date_time == DateTimeCrate::Time {\n                    return Err(Error::DateTimeCrateFeatureNotEnabled);\n                }\n\n                #[cfg(feature = \"chrono\")]\n                if matches!(preferred_crates.date_time, DateTimeCrate::Chrono | DateTimeCrate::Inferred) {\n                    $(\n                        if <$chrono_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            return Ok($crate::select_input_type!($chrono_ty $(, $chrono_input)?));\n                        }\n                    )*\n\n                    $(\n                        if <$chrono_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            return Ok($crate::select_input_type!($chrono_ty $(, $chrono_input)?));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"chrono\"))]\n                if preferred_crates.date_time == DateTimeCrate::Chrono {\n                    return Err(Error::DateTimeCrateFeatureNotEnabled);\n                }\n\n                // Check `macros.preferred-crates.numeric`\n                //\n                // Due to legacy reasons, `bigdecimal` takes precedent over `rust_decimal` if\n                // both are enabled.\n                // ----------------------------------------\n                #[cfg(feature = \"bigdecimal\")]\n                if matches!(preferred_crates.numeric, NumericCrate::BigDecimal | NumericCrate::Inferred) {\n                    $(\n                        if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            if cfg!(feature = \"rust_decimal\") {\n                                return Err($crate::type_checking::Error::AmbiguousNumericType {\n                                    fallback: $crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?),\n                                });\n                            }\n\n                            return Ok($crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?));\n                        }\n                    )*\n\n                    $(\n                        if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            if cfg!(feature = \"rust_decimal\") {\n                                return Err($crate::type_checking::Error::AmbiguousNumericType {\n                                    fallback: $crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?),\n                                });\n                            }\n\n                            return Ok($crate::select_input_type!($bigdecimal_ty $(, $bigdecimal_input)?));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"bigdecimal\"))]\n                if preferred_crates.numeric == NumericCrate::BigDecimal {\n                    return Err(Error::NumericCrateFeatureNotEnabled);\n                }\n\n                #[cfg(feature = \"rust_decimal\")]\n                if matches!(preferred_crates.numeric, NumericCrate::RustDecimal | NumericCrate::Inferred) {\n                    $(\n                        if <$rust_decimal_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            return Ok($crate::select_input_type!($rust_decimal_ty $(, $rust_decimal_input)?));\n                        }\n                    )*\n\n                    $(\n                        if <$rust_decimal_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            return Ok($crate::select_input_type!($rust_decimal_ty $(, $rust_decimal_input)?));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"rust_decimal\"))]\n                if preferred_crates.numeric == NumericCrate::RustDecimal {\n                    return Err(Error::NumericCrateFeatureNotEnabled);\n                }\n\n                Err(Error::NoMappingFound)\n            }\n\n            fn return_type_for_id(\n                info: &Self::TypeInfo,\n                preferred_crates: &$crate::config::macros::PreferredCrates,\n            ) -> Result<&'static str, $crate::type_checking::Error> {\n                use $crate::config::macros::{DateTimeCrate, NumericCrate};\n                use $crate::type_checking::Error;\n\n                // Check non-special types\n                // ---------------------\n                $(\n                    $(#[$meta])?\n                    if <$ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                        return Ok(stringify!($ty));\n                    }\n                )*\n\n                $(\n                    $(#[$meta])?\n                    if <$ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                        return Ok(stringify!($ty));\n                    }\n                )*\n\n                // Check `macros.preferred-crates.date-time`\n                //\n                // Due to legacy reasons, `time` takes precedent over `chrono` if both are enabled.\n                // Any crates added later should be _lower_ priority than `chrono` to avoid breakages.\n                // ----------------------------------------\n                #[cfg(feature = \"time\")]\n                if matches!(preferred_crates.date_time, DateTimeCrate::Time | DateTimeCrate::Inferred) {\n                    $(\n                        if <$time_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            if cfg!(feature = \"chrono\") {\n                                return Err($crate::type_checking::Error::AmbiguousDateTimeType {\n                                    fallback: stringify!($time_ty),\n                                });\n                            }\n\n                            return Ok(stringify!($time_ty));\n                        }\n                    )*\n\n                    $(\n                        if <$time_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            if cfg!(feature = \"chrono\") {\n                                return Err($crate::type_checking::Error::AmbiguousDateTimeType {\n                                    fallback: stringify!($time_ty),\n                                });\n                            }\n\n                            return Ok(stringify!($time_ty));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"time\"))]\n                if preferred_crates.date_time == DateTimeCrate::Time {\n                    return Err(Error::DateTimeCrateFeatureNotEnabled);\n                }\n\n                #[cfg(feature = \"chrono\")]\n                if matches!(preferred_crates.date_time, DateTimeCrate::Chrono | DateTimeCrate::Inferred) {\n                    $(\n                        if <$chrono_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            return Ok(stringify!($chrono_ty));\n                        }\n                    )*\n\n                    $(\n                        if <$chrono_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            return Ok(stringify!($chrono_ty));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"chrono\"))]\n                if preferred_crates.date_time == DateTimeCrate::Chrono {\n                    return Err(Error::DateTimeCrateFeatureNotEnabled);\n                }\n\n                // Check `macros.preferred-crates.numeric`\n                //\n                // Due to legacy reasons, `bigdecimal` takes precedent over `rust_decimal` if\n                // both are enabled.\n                // ----------------------------------------\n                #[cfg(feature = \"bigdecimal\")]\n                if matches!(preferred_crates.numeric, NumericCrate::BigDecimal | NumericCrate::Inferred) {\n                    $(\n                        if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            if cfg!(feature = \"rust_decimal\") {\n                                return Err($crate::type_checking::Error::AmbiguousNumericType {\n                                    fallback: stringify!($bigdecimal_ty),\n                                });\n                            }\n\n                            return Ok(stringify!($bigdecimal_ty));\n                        }\n                    )*\n\n                    $(\n                        if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            if cfg!(feature = \"rust_decimal\") {\n                                return Err($crate::type_checking::Error::AmbiguousNumericType {\n                                    fallback: stringify!($bigdecimal_ty),\n                                });\n                            }\n\n                            return Ok(stringify!($bigdecimal_ty));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"bigdecimal\"))]\n                if preferred_crates.numeric == NumericCrate::BigDecimal {\n                    return Err(Error::NumericCrateFeatureNotEnabled);\n                }\n\n                #[cfg(feature = \"rust_decimal\")]\n                if matches!(preferred_crates.numeric, NumericCrate::RustDecimal | NumericCrate::Inferred) {\n                    $(\n                        if <$rust_decimal_ty as sqlx_core::types::Type<$database>>::type_info() == *info {\n                            return Ok($crate::select_input_type!($rust_decimal_ty $(, $rust_decimal_input)?));\n                        }\n                    )*\n\n                    $(\n                        if <$rust_decimal_ty as sqlx_core::types::Type<$database>>::compatible(info) {\n                            return Ok($crate::select_input_type!($rust_decimal_ty $(, $rust_decimal_input)?));\n                        }\n                    )*\n                }\n\n                #[cfg(not(feature = \"rust_decimal\"))]\n                if preferred_crates.numeric == NumericCrate::RustDecimal {\n                    return Err(Error::NumericCrateFeatureNotEnabled);\n                }\n\n                Err(Error::NoMappingFound)\n            }\n\n            fn get_feature_gate($ty_info: &Self::TypeInfo) -> Option<&'static str> {\n                $get_gate\n            }\n\n            fn fmt_value_debug(value: &Self::Value) -> $crate::type_checking::FmtValue<Self> {\n                use $crate::value::Value;\n\n                let info = value.type_info();\n\n                #[cfg(feature = \"time\")]\n                {\n                    $(\n                        if <$time_ty as sqlx_core::types::Type<$database>>::compatible(&info) {\n                            return $crate::type_checking::FmtValue::debug::<$time_ty>(value);\n                        }\n                    )*\n                }\n\n                #[cfg(feature = \"chrono\")]\n                {\n                    $(\n                        if <$chrono_ty as sqlx_core::types::Type<$database>>::compatible(&info) {\n                            return $crate::type_checking::FmtValue::debug::<$chrono_ty>(value);\n                        }\n                    )*\n                }\n\n                #[cfg(feature = \"bigdecimal\")]\n                {\n                    $(\n                        if <$bigdecimal_ty as sqlx_core::types::Type<$database>>::compatible(&info) {\n                            return $crate::type_checking::FmtValue::debug::<$bigdecimal_ty>(value);\n                        }\n                    )*\n                }\n\n                #[cfg(feature = \"rust_decimal\")]\n                {\n                    $(\n                        if <$rust_decimal_ty as sqlx_core::types::Type<$database>>::compatible(&info) {\n                            return $crate::type_checking::FmtValue::debug::<$rust_decimal_ty>(value);\n                        }\n                    )*\n                }\n\n                $(\n                    $(#[$meta])?\n                    if <$ty as sqlx_core::types::Type<$database>>::compatible(&info) {\n                        return $crate::type_checking::FmtValue::debug::<$ty>(value);\n                    }\n                )*\n\n                $crate::type_checking::FmtValue::unknown(value)\n            }\n        }\n    };\n}\n"
  },
  {
    "path": "sqlx-core/src/type_info.rs",
    "content": "use std::fmt::{Debug, Display};\n\n/// Provides information about a SQL type for the database driver.\npub trait TypeInfo: Debug + Display + Clone + PartialEq<Self> + Send + Sync {\n    fn is_null(&self) -> bool;\n\n    /// Returns the database system name of the type. Length specifiers should not be included.\n    /// Common type names are `VARCHAR`, `TEXT`, or `INT`. Type names should be uppercase. They\n    /// should be a rough approximation of how they are written in SQL in the given database.\n    fn name(&self) -> &str;\n\n    /// Return `true` if `self` and `other` represent mutually compatible types.\n    ///\n    /// Defaults to `self == other`.\n    fn type_compatible(&self, other: &Self) -> bool\n    where\n        Self: Sized,\n    {\n        self == other\n    }\n\n    #[doc(hidden)]\n    fn is_void(&self) -> bool {\n        false\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/types/bstr.rs",
    "content": "/// Conversions between `bstr` types and SQL types.\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\n\n#[doc(no_inline)]\npub use bstr::{BStr, BString, ByteSlice};\n\nimpl<DB> Type<DB> for BString\nwhere\n    DB: Database,\n    [u8]: Type<DB>,\n{\n    fn type_info() -> DB::TypeInfo {\n        <&[u8] as Type<DB>>::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        <&[u8] as Type<DB>>::compatible(ty)\n    }\n}\n\nimpl<'r, DB> Decode<'r, DB> for BString\nwhere\n    DB: Database,\n    Vec<u8>: Decode<'r, DB>,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        <Vec<u8> as Decode<DB>>::decode(value).map(BString::from)\n    }\n}\n\nimpl<'q, DB: Database> Encode<'q, DB> for &'q BStr\nwhere\n    DB: Database,\n    &'q [u8]: Encode<'q, DB>,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <&[u8] as Encode<DB>>::encode(self.as_bytes(), buf)\n    }\n}\n\nimpl<'q, DB: Database> Encode<'q, DB> for BString\nwhere\n    DB: Database,\n    Vec<u8>: Encode<'q, DB>,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <Vec<u8> as Encode<DB>>::encode(self.as_bytes().to_vec(), buf)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/types/json.rs",
    "content": "use std::ops::{Deref, DerefMut};\n\nuse serde::{Deserialize, Serialize};\npub use serde_json::value::RawValue as JsonRawValue;\npub use serde_json::Value as JsonValue;\n\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\n\n/// Json for json and jsonb fields\n///\n/// Will attempt to cast to type passed in as the generic.\n///\n/// ```toml\n/// [dependencies]\n/// serde_json = { version = \"1.0\", features = [\"raw_value\"] }\n///\n/// ```\n///\n/// # Example\n///\n/// ```\n/// # use serde::Deserialize;\n/// #[derive(Deserialize)]\n/// struct Book {\n///   name: String\n/// }\n///\n/// #[derive(sqlx::FromRow)]\n/// struct Author {\n///   name: String,\n///   books: sqlx::types::Json<Book>\n/// }\n/// ```\n///\n/// Can also be used to turn the json/jsonb into a hashmap\n/// ```\n/// use std::collections::HashMap;\n/// use serde::Deserialize;\n///\n/// #[derive(Deserialize)]\n/// struct Book {\n///   name: String\n/// }\n/// #[derive(sqlx::FromRow)]\n/// struct Library {\n///   id: String,\n///   dewey_decimal: sqlx::types::Json<HashMap<String, Book>>\n/// }\n/// ```\n///\n/// If the query macros are used, it is necessary to tell the macro to use\n/// the `Json` adapter by using the type override syntax\n/// ```rust,ignore\n/// # async fn example3() -> sqlx::Result<()> {\n/// # let mut conn: sqlx::PgConnection = unimplemented!();\n/// #[derive(sqlx::FromRow)]\n/// struct Book {\n///     title: String,\n/// }\n///\n/// #[derive(sqlx::FromRow)]\n/// struct Author {\n///     name: String,\n///     books: sqlx::types::Json<Book>,\n/// }\n/// // Note the type override in the query string\n/// let authors = sqlx::query_as!(\n///     Author,\n///     r#\"\n/// SELECT name, books as \"books: Json<Book>\"\n/// FROM authors\n///     \"#\n/// )\n/// .fetch_all(&mut conn)\n/// .await?;\n/// # Ok(())\n/// # }\n/// ```\n#[derive(\n    Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize,\n)]\n#[serde(transparent)]\npub struct Json<T: ?Sized>(pub T);\n\nimpl<T> Json<T> {\n    /// Extract the inner value.\n    pub fn into_inner(self) -> T {\n        self.0\n    }\n}\n\nimpl<T> From<T> for Json<T> {\n    fn from(value: T) -> Self {\n        Self(value)\n    }\n}\n\nimpl<T> Deref for Json<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<T> DerefMut for Json<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\nimpl<T> AsRef<T> for Json<T> {\n    fn as_ref(&self) -> &T {\n        &self.0\n    }\n}\n\nimpl<T> AsMut<T> for Json<T> {\n    fn as_mut(&mut self) -> &mut T {\n        &mut self.0\n    }\n}\n\n// UNSTABLE: for driver use only!\n#[doc(hidden)]\nimpl<T: Serialize> Json<T> {\n    pub fn encode_to_string(&self) -> Result<String, serde_json::Error> {\n        serde_json::to_string(self)\n    }\n\n    pub fn encode_to(&self, buf: &mut Vec<u8>) -> Result<(), serde_json::Error> {\n        serde_json::to_writer(buf, self)\n    }\n}\n\n// UNSTABLE: for driver use only!\n#[doc(hidden)]\nimpl<'a, T: 'a> Json<T>\nwhere\n    T: Deserialize<'a>,\n{\n    pub fn decode_from_string(s: &'a str) -> Result<Self, BoxDynError> {\n        serde_json::from_str(s).map_err(Into::into)\n    }\n\n    pub fn decode_from_bytes(bytes: &'a [u8]) -> Result<Self, BoxDynError> {\n        serde_json::from_slice(bytes).map_err(Into::into)\n    }\n}\n\nimpl<DB> Type<DB> for JsonValue\nwhere\n    Json<Self>: Type<DB>,\n    DB: Database,\n{\n    fn type_info() -> DB::TypeInfo {\n        <Json<Self> as Type<DB>>::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        <Json<Self> as Type<DB>>::compatible(ty)\n    }\n}\n\nimpl<'q, DB> Encode<'q, DB> for JsonValue\nwhere\n    for<'a> Json<&'a Self>: Encode<'q, DB>,\n    DB: Database,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <Json<&Self> as Encode<'q, DB>>::encode(Json(self), buf)\n    }\n}\n\nimpl<'r, DB> Decode<'r, DB> for JsonValue\nwhere\n    Json<Self>: Decode<'r, DB>,\n    DB: Database,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        <Json<Self> as Decode<DB>>::decode(value).map(|item| item.0)\n    }\n}\n\nimpl<DB> Type<DB> for JsonRawValue\nwhere\n    for<'a> Json<&'a Self>: Type<DB>,\n    DB: Database,\n{\n    fn type_info() -> DB::TypeInfo {\n        <Json<&Self> as Type<DB>>::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        <Json<&Self> as Type<DB>>::compatible(ty)\n    }\n}\n\nimpl<'q, DB> Encode<'q, DB> for JsonRawValue\nwhere\n    for<'a> Json<&'a Self>: Encode<'q, DB>,\n    DB: Database,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <Json<&Self> as Encode<'q, DB>>::encode(Json(self), buf)\n    }\n}\n\nimpl<'q, DB> Encode<'q, DB> for &'q JsonRawValue\nwhere\n    for<'a> Json<&'a Self>: Encode<'q, DB>,\n    DB: Database,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <Json<&Self> as Encode<'q, DB>>::encode(Json(self), buf)\n    }\n}\n\nimpl<'q, DB> Encode<'q, DB> for Box<JsonRawValue>\nwhere\n    for<'a> Json<&'a Self>: Encode<'q, DB>,\n    DB: Database,\n{\n    fn encode_by_ref(\n        &self,\n        buf: &mut <DB as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        <Json<&Self> as Encode<'q, DB>>::encode(Json(self), buf)\n    }\n}\n\nimpl<'r, DB> Decode<'r, DB> for &'r JsonRawValue\nwhere\n    Json<Self>: Decode<'r, DB>,\n    DB: Database,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        <Json<Self> as Decode<DB>>::decode(value).map(|item| item.0)\n    }\n}\n\nimpl<'r, DB> Decode<'r, DB> for Box<JsonRawValue>\nwhere\n    Json<Self>: Decode<'r, DB>,\n    DB: Database,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        <Json<Self> as Decode<DB>>::decode(value).map(|item| item.0)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/types/mod.rs",
    "content": "//! Conversions between Rust and SQL types.\n//!\n//! To see how each SQL type maps to a Rust type, see the corresponding `types` module for each\n//! database:\n//!\n//!  * [PostgreSQL](crate::postgres::types)\n//!  * [MySQL](crate::mysql::types)\n//!  * [SQLite](crate::sqlite::types)\n//!  * [MSSQL](crate::mssql::types)\n//!\n//! Any external types that have had [`Type`] implemented for, are re-exported in this module\n//! for convenience as downstream users need to use a compatible version of the external crate\n//! to take advantage of the implementation.\n//!\n//! # Nullable\n//!\n//! To represent nullable SQL types, `Option<T>` is supported where `T` implements `Type`.\n//! An `Option<T>` represents a potentially `NULL` value from SQL.\n\nuse std::{borrow::Cow, rc::Rc, sync::Arc};\n\nuse crate::database::Database;\nuse crate::type_info::TypeInfo;\n\nmod non_zero;\n\n#[cfg(feature = \"bstr\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"bstr\")))]\npub mod bstr;\n\n#[cfg(feature = \"json\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"json\")))]\nmod json;\n\nmod text;\n\n#[cfg(feature = \"uuid\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"uuid\")))]\n#[doc(no_inline)]\npub use uuid::{self, Uuid};\n\n#[cfg(feature = \"chrono\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"chrono\")))]\npub mod chrono {\n    #[doc(no_inline)]\n    pub use chrono::{\n        DateTime, FixedOffset, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,\n    };\n}\n\n#[cfg(feature = \"bit-vec\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"bit-vec\")))]\n#[doc(no_inline)]\npub use bit_vec::BitVec;\n\n#[cfg(feature = \"time\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"time\")))]\npub mod time {\n    #[doc(no_inline)]\n    pub use time::{Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};\n}\n\n#[cfg(feature = \"bigdecimal\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"bigdecimal\")))]\n#[doc(no_inline)]\npub use bigdecimal::BigDecimal;\n#[cfg(feature = \"rust_decimal\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"rust_decimal\")))]\n#[doc(no_inline)]\npub use rust_decimal::Decimal;\n\n#[cfg(feature = \"ipnet\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"ipnet\")))]\npub mod ipnet {\n    #[doc(no_inline)]\n    pub use ipnet::{IpNet, Ipv4Net, Ipv6Net};\n}\n\n#[cfg(feature = \"ipnetwork\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"ipnetwork\")))]\npub mod ipnetwork {\n    #[doc(no_inline)]\n    pub use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};\n}\n\n#[cfg(feature = \"mac_address\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"mac_address\")))]\npub mod mac_address {\n    #[doc(no_inline)]\n    pub use mac_address::MacAddress;\n}\n\n#[cfg(feature = \"json\")]\npub use json::{Json, JsonRawValue, JsonValue};\npub use text::Text;\n\n#[cfg(feature = \"bstr\")]\npub use bstr::{BStr, BString};\n\n/// Indicates that a SQL type is supported for a database.\n///\n/// ## Compile-time verification\n///\n/// Type definitions are *not* verified against the database at compile-time.\n/// The [`query!()`](macro.query.html) macros have no implicit knowledge of user-defined types.\n///\n/// When using custom types in query parameters or output columns with `query!()`,\n/// the use of [type overrides](macro.query.html#type-overrides-bind-parameters-postgres-only) is required.\n///\n/// ```rust,ignore\n/// struct MyUser { id: UserId, name: String }\n///\n/// // fetch all properties from user and override the type in Rust for `id`\n/// let user = query_as!(MyUser, r#\"SELECT users.*, id as \"id: UserId\" FROM users\"#)\n///     .fetch_one(&pool).await?;\n/// ```\n///\n/// ## Derivable\n///\n/// This trait can be derived by SQLx to support Rust-only wrapper types, enumerations, and (for\n/// postgres) structured records. Additionally, an implementation of [`Encode`](crate::encode::Encode) and [`Decode`](crate::decode::Decode) is\n/// generated.\n///\n/// ### Transparent\n///\n/// Rust-only domain wrappers around SQL types. The generated implementations directly delegate\n/// to the implementation of the inner type.\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent)]\n/// struct UserId(i64);\n/// ```\n///\n/// ##### Note: `PgHasArrayType`\n/// If you have the `postgres` feature enabled, this derive also generates a `PgHasArrayType` impl\n/// so that you may use it with `Vec` and other types that decode from an array in Postgres:\n///\n/// ```rust,ignore\n/// let user_ids: Vec<UserId> = sqlx::query_scalar(\"select '{ 123, 456 }'::int8[]\")\n///    .fetch(&mut pg_connection)\n///    .await?;\n/// ```\n///\n/// However, if you are wrapping a type that does not implement `PgHasArrayType`\n/// (e.g. `Vec` itself, because we don't currently support multidimensional arrays),\n/// you may receive an error:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)] // ERROR: `Vec<i64>` does not implement `PgHasArrayType`\n/// #[sqlx(transparent)]\n/// struct UserIds(Vec<i64>);\n/// ```\n///\n/// To remedy this, add `#[sqlx(no_pg_array)]`, which disables the generation\n/// of the `PgHasArrayType` impl:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent, no_pg_array)]\n/// struct UserIds(Vec<i64>);\n/// ```\n///\n/// ##### Attributes\n///\n/// * `#[sqlx(type_name = \"<SQL type name>\")]` on struct definition: instead of inferring the SQL\n///   type name from the inner field (in the above case, `BIGINT`), explicitly set it to\n///   `<SQL type name>` instead. May trigger errors or unexpected behavior if the encoding of the\n///   given type is different than that of the inferred type (e.g. if you rename the above to\n///   `VARCHAR`). Affects Postgres only.\n/// * `#[sqlx(rename_all = \"<strategy>\")]` on struct definition: See [`derive docs in FromRow`](crate::from_row::FromRow#rename_all)\n/// * `#[sqlx(no_pg_array)]`: do not emit a `PgHasArrayType` impl (see above).\n///\n/// ### Enumeration\n///\n/// Enumerations may be defined in Rust and can match SQL by\n/// integer discriminant or variant name.\n///\n/// With `#[repr(_)]` the integer representation is used when converting from/to SQL and expects\n/// that SQL type (e.g., `INT`). Without, the names of the variants are used instead and\n/// expects a textual SQL type (e.g., `VARCHAR`, `TEXT`).\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[repr(i32)]\n/// enum Color { Red = 1, Green = 2, Blue = 3 }\n/// ```\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(type_name = \"color\")] // only for PostgreSQL to match a type definition\n/// #[sqlx(rename_all = \"lowercase\")]\n/// enum Color { Red, Green, Blue }\n/// ```\n///\n/// ### Records\n///\n/// User-defined composite types are supported through deriving a `struct`.\n///\n/// This is only supported for PostgreSQL.\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(type_name = \"interface_type\")]\n/// struct InterfaceType {\n///     name: String,\n///     supplier_id: i32,\n///     price: f64\n/// }\n/// ```\npub trait Type<DB: Database> {\n    /// Returns the canonical SQL type for this Rust type.\n    ///\n    /// When binding arguments, this is used to tell the database what is about to be sent; which,\n    /// the database then uses to guide query plans. This can be overridden by `Encode::produces`.\n    ///\n    /// A map of SQL types to Rust types is populated with this and used\n    /// to determine the type that is returned from the anonymous struct type from `query!`.\n    fn type_info() -> DB::TypeInfo;\n\n    /// Determines if this Rust type is compatible with the given SQL type.\n    ///\n    /// When decoding values from a row, this method is checked to determine if we should continue\n    /// or raise a runtime type mismatch error.\n    ///\n    /// When binding arguments with `query!` or `query_as!`, this method is consulted to determine\n    /// if the Rust type is acceptable.\n    ///\n    /// Defaults to checking [`TypeInfo::type_compatible()`].\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        Self::type_info().type_compatible(ty)\n    }\n}\n\n// for references, the underlying SQL type is identical\nimpl<T: ?Sized + Type<DB>, DB: Database> Type<DB> for &'_ T {\n    fn type_info() -> DB::TypeInfo {\n        <T as Type<DB>>::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        <T as Type<DB>>::compatible(ty)\n    }\n}\n\n// for optionals, the underlying SQL type is identical\nimpl<T: Type<DB>, DB: Database> Type<DB> for Option<T> {\n    fn type_info() -> DB::TypeInfo {\n        <T as Type<DB>>::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        ty.is_null() || <T as Type<DB>>::compatible(ty)\n    }\n}\n\nmacro_rules! impl_type_for_smartpointer {\n    ($smart_pointer:ty) => {\n        impl<T, DB: Database> Type<DB> for $smart_pointer\n        where\n            T: Type<DB> + ?Sized,\n        {\n            fn type_info() -> DB::TypeInfo {\n                <T as Type<DB>>::type_info()\n            }\n\n            fn compatible(ty: &DB::TypeInfo) -> bool {\n                <T as Type<DB>>::compatible(ty)\n            }\n        }\n    };\n}\n\nimpl_type_for_smartpointer!(Arc<T>);\nimpl_type_for_smartpointer!(Box<T>);\nimpl_type_for_smartpointer!(Rc<T>);\n\nimpl<T, DB: Database> Type<DB> for Cow<'_, T>\nwhere\n    // `ToOwned` is required here to satisfy `Cow`\n    T: Type<DB> + ToOwned + ?Sized,\n{\n    fn type_info() -> DB::TypeInfo {\n        <T as Type<DB>>::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        <T as Type<DB>>::compatible(ty)\n    }\n}\n"
  },
  {
    "path": "sqlx-core/src/types/non_zero.rs",
    "content": "//! [`Type`], [`Encode`], and [`Decode`] implementations for the various [`NonZero*`][non-zero]\n//! types from the standard library.\n//!\n//! [non-zero]: core::num::NonZero\n\nuse std::num::{\n    NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8,\n};\n\nuse crate::database::Database;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::types::Type;\n\nmacro_rules! impl_non_zero {\n    ($($int:ty => $non_zero:ty),* $(,)?) => {\n        $(impl<DB> Type<DB> for $non_zero\n        where\n            DB: Database,\n            $int: Type<DB>,\n        {\n            fn type_info() -> <DB as Database>::TypeInfo {\n                <$int as Type<DB>>::type_info()\n            }\n\n            fn compatible(ty: &<DB as Database>::TypeInfo) -> bool {\n                <$int as Type<DB>>::compatible(ty)\n            }\n        }\n\n        impl<'q, DB> Encode<'q, DB> for $non_zero\n        where\n            DB: Database,\n            $int: Encode<'q, DB>,\n        {\n            fn encode_by_ref(&self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, crate::error::BoxDynError> {\n                <$int as Encode<'q, DB>>::encode_by_ref(&self.get(), buf)\n            }\n\n            fn encode(self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, crate::error::BoxDynError>\n            where\n                Self: Sized,\n            {\n                <$int as Encode<'q, DB>>::encode(self.get(), buf)\n            }\n\n            fn produces(&self) -> Option<<DB as Database>::TypeInfo> {\n                <$int as Encode<'q, DB>>::produces(&self.get())\n            }\n        }\n\n        impl<'r, DB> Decode<'r, DB> for $non_zero\n        where\n            DB: Database,\n            $int: Decode<'r, DB>,\n        {\n            fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, crate::error::BoxDynError> {\n                let int = <$int as Decode<'r, DB>>::decode(value)?;\n                let non_zero = Self::try_from(int)?;\n\n                Ok(non_zero)\n            }\n        })*\n    };\n}\n\nimpl_non_zero! {\n    i8 => NonZeroI8,\n    u8 => NonZeroU8,\n    i16 => NonZeroI16,\n    u16 => NonZeroU16,\n    i32 => NonZeroI32,\n    u32 => NonZeroU32,\n    i64 => NonZeroI64,\n    u64 => NonZeroU64,\n}\n"
  },
  {
    "path": "sqlx-core/src/types/text.rs",
    "content": "use std::ops::{Deref, DerefMut};\n\n/// Map a SQL text value to/from a Rust type using [`Display`] and [`FromStr`].\n///\n/// This can be useful for types that do not have a direct SQL equivalent, or are simply not\n/// supported by SQLx for one reason or another.\n///\n/// For strongly typed databases like Postgres, this will report the value's type as `TEXT`.\n/// Explicit conversion may be necessary on the SQL side depending on the desired type.\n///\n/// [`Display`]: std::fmt::Display\n/// [`FromStr`]: std::str::FromStr\n///\n/// ### Panics\n///\n/// You should only use this adapter with `Display` implementations that are infallible,\n/// otherwise you may encounter panics when attempting to bind a value.\n///\n/// This is because the design of the `Encode` trait assumes encoding is infallible, so there is no\n/// way to bubble up the error.\n///\n/// Fortunately, most `Display` implementations are infallible by convention anyway\n/// (the standard `ToString` trait also assumes this), but you may still want to audit\n/// the source code for any types you intend to use with this adapter, just to be safe.\n///\n/// ### Example: `SocketAddr`\n///\n/// MySQL and SQLite do not have a native SQL equivalent for `SocketAddr`, so if you want to\n/// store and retrieve instances of it, it makes sense to map it to `TEXT`:\n///\n/// ```rust,no_run\n/// # use sqlx::types::{time, uuid};\n///\n/// use std::net::SocketAddr;\n///\n/// use sqlx::Connection;\n/// use sqlx::mysql::MySqlConnection;\n/// use sqlx::types::Text;\n///\n/// use uuid::Uuid;\n/// use time::OffsetDateTime;\n///\n/// #[derive(sqlx::FromRow, Debug)]\n/// struct Login {\n///     user_id: Uuid,\n///     socket_addr: Text<SocketAddr>,\n///     login_at: OffsetDateTime\n/// }\n///\n/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {\n///\n/// let mut conn: MySqlConnection = MySqlConnection::connect(\"<DATABASE URL>\").await?;\n///\n/// let user_id: Uuid = \"e9a72cdc-d907-48d6-a488-c64a91fd063c\".parse().unwrap();\n/// let socket_addr: SocketAddr = \"198.51.100.47:31790\".parse().unwrap();\n///\n/// // CREATE TABLE user_login(user_id VARCHAR(36), socket_addr TEXT, login_at TIMESTAMP);\n/// sqlx::query(\"INSERT INTO user_login(user_id, socket_addr, login_at) VALUES (?, ?, NOW())\")\n///     .bind(user_id)\n///     .bind(Text(socket_addr))\n///     .execute(&mut conn)\n///     .await?;\n///\n/// let logins: Vec<Login> = sqlx::query_as(\"SELECT * FROM user_login\")\n///     .fetch_all(&mut conn)\n///     .await?;\n///\n/// println!(\"Logins for user ID {user_id}: {logins:?}\");\n///\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]\npub struct Text<T>(pub T);\n\nimpl<T> Text<T> {\n    /// Extract the inner value.\n    pub fn into_inner(self) -> T {\n        self.0\n    }\n}\n\nimpl<T> Deref for Text<T> {\n    type Target = T;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl<T> DerefMut for Text<T> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\n/* We shouldn't use blanket impls so individual drivers can provide specialized ones.\nimpl<T, DB> Type<DB> for Text<T>\nwhere\n    String: Type<DB>,\n    DB: Database,\n{\n    fn type_info() -> DB::TypeInfo {\n        String::type_info()\n    }\n\n    fn compatible(ty: &DB::TypeInfo) -> bool {\n        String::compatible(ty)\n    }\n}\n\nimpl<'q, T, DB> Encode<'q, DB> for Text<T>\nwhere\n    T: Display,\n    String: Encode<'q, DB>,\n    DB: Database,\n{\n    fn encode_by_ref(&self, buf: &mut <DB as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.0.to_string().encode(buf)\n    }\n}\n\nimpl<'r, T, DB> Decode<'r, DB> for Text<T>\nwhere\n    T: FromStr,\n    BoxDynError: From<<T as FromStr>::Err>,\n    &'r str: Decode<'r, DB>,\n    DB: Database,\n{\n    fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(Text(<&'r str as Decode<'r, DB>>::decode(value)?.parse()?))\n    }\n}\n*/\n"
  },
  {
    "path": "sqlx-core/src/value.rs",
    "content": "use crate::database::Database;\nuse crate::decode::Decode;\nuse crate::error::{mismatched_types, Error};\nuse crate::type_info::TypeInfo;\nuse crate::types::Type;\nuse std::borrow::Cow;\n\n/// An owned value from the database.\npub trait Value {\n    type Database: Database<Value = Self>;\n\n    /// Get this value as a reference.\n    fn as_ref(&self) -> <Self::Database as Database>::ValueRef<'_>;\n\n    /// Get the type information for this value.\n    fn type_info(&self) -> Cow<'_, <Self::Database as Database>::TypeInfo>;\n\n    /// Returns `true` if the SQL value is `NULL`.\n    fn is_null(&self) -> bool;\n\n    /// Decode this single value into the requested type.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the value cannot be decoded into the requested type.\n    /// See [`try_decode`](Self::try_decode) for a non-panicking version.\n    ///\n    #[inline]\n    fn decode<'r, T>(&'r self) -> T\n    where\n        T: Decode<'r, Self::Database> + Type<Self::Database>,\n    {\n        self.try_decode::<T>().unwrap()\n    }\n\n    /// Decode this single value into the requested type.\n    ///\n    /// Unlike [`decode`](Self::decode), this method does not check that the type of this\n    /// value is compatible with the Rust type and blindly tries to decode the value.\n    ///\n    /// # Panics\n    ///\n    /// Panics if the value cannot be decoded into the requested type.\n    /// See [`try_decode_unchecked`](Self::try_decode_unchecked) for a non-panicking version.\n    ///\n    #[inline]\n    fn decode_unchecked<'r, T>(&'r self) -> T\n    where\n        T: Decode<'r, Self::Database>,\n    {\n        self.try_decode_unchecked::<T>().unwrap()\n    }\n\n    /// Decode this single value into the requested type.\n    ///\n    /// # Errors\n    ///\n    ///  * [`Decode`] if the value could not be decoded into the requested type.\n    ///\n    /// [`Decode`]: Error::Decode\n    ///\n    #[inline]\n    fn try_decode<'r, T>(&'r self) -> Result<T, Error>\n    where\n        T: Decode<'r, Self::Database> + Type<Self::Database>,\n    {\n        if !self.is_null() {\n            let ty = self.type_info();\n\n            if !ty.is_null() && !T::compatible(&ty) {\n                return Err(Error::Decode(mismatched_types::<Self::Database, T>(&ty)));\n            }\n        }\n\n        self.try_decode_unchecked()\n    }\n\n    /// Decode this single value into the requested type.\n    ///\n    /// Unlike [`try_decode`](Self::try_decode), this method does not check that the type of this\n    /// value is compatible with the Rust type and blindly tries to decode the value.\n    ///\n    /// # Errors\n    ///\n    ///  * [`Decode`] if the value could not be decoded into the requested type.\n    ///\n    /// [`Decode`]: Error::Decode\n    ///\n    #[inline]\n    fn try_decode_unchecked<'r, T>(&'r self) -> Result<T, Error>\n    where\n        T: Decode<'r, Self::Database>,\n    {\n        T::decode(self.as_ref()).map_err(Error::Decode)\n    }\n}\n\n/// A reference to a single value from the database.\npub trait ValueRef<'r>: Sized {\n    type Database: Database;\n\n    /// Creates an owned value from this value reference.\n    ///\n    /// This is just a reference increment in PostgreSQL and MySQL and thus is `O(1)`. In SQLite,\n    /// this is a copy.\n    fn to_owned(&self) -> <Self::Database as Database>::Value;\n\n    /// Get the type information for this value.\n    fn type_info(&self) -> Cow<'_, <Self::Database as Database>::TypeInfo>;\n\n    /// Returns `true` if the SQL value is `NULL`.\n    fn is_null(&self) -> bool;\n}\n"
  },
  {
    "path": "sqlx-macros/Cargo.toml",
    "content": "[package]\nname = \"sqlx-macros\"\ndescription = \"Macros for SQLx, the rust SQL toolkit. Not intended to be used directly.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n[lib]\nproc-macro = true\n\n[features]\ndefault = []\n\n# for conditional compilation\n_rt-async-global-executor = [\"sqlx-macros-core/_rt-async-global-executor\"]\n_rt-async-std = [\"sqlx-macros-core/_rt-async-std\"]\n_rt-smol = [\"sqlx-macros-core/_rt-smol\"]\n_rt-tokio = [\"sqlx-macros-core/_rt-tokio\"]\n\n_tls-native-tls = [\"sqlx-macros-core/_tls-native-tls\"]\n_tls-rustls-aws-lc-rs = [\"sqlx-macros-core/_tls-rustls-aws-lc-rs\"]\n_tls-rustls-ring-webpki = [\"sqlx-macros-core/_tls-rustls-ring-webpki\"]\n_tls-rustls-ring-native-roots = [\"sqlx-macros-core/_tls-rustls-ring-native-roots\"]\n\n# SQLx features\nderive = [\"sqlx-macros-core/derive\"]\nmacros = [\"sqlx-macros-core/macros\"]\nmigrate = [\"sqlx-macros-core/migrate\"]\n\nsqlx-toml = [\"sqlx-macros-core/sqlx-toml\"]\n\n# database\nmysql = [\"sqlx-macros-core/mysql\"]\npostgres = [\"sqlx-macros-core/postgres\"]\nsqlite = [\"sqlx-macros-core/sqlite\"]\nsqlite-unbundled = [\"sqlx-macros-core/sqlite-unbundled\"]\n\nsqlite-load-extension = [\"sqlx-macros-core/sqlite-load-extension\"]\n\n# type\nbigdecimal = [\"sqlx-macros-core/bigdecimal\"]\nbit-vec = [\"sqlx-macros-core/bit-vec\"]\nchrono = [\"sqlx-macros-core/chrono\"]\nipnet = [\"sqlx-macros-core/ipnet\"]\nipnetwork = [\"sqlx-macros-core/ipnetwork\"]\nmac_address = [\"sqlx-macros-core/mac_address\"]\nrust_decimal = [\"sqlx-macros-core/rust_decimal\"]\ntime = [\"sqlx-macros-core/time\"]\nuuid = [\"sqlx-macros-core/uuid\"]\njson = [\"sqlx-macros-core/json\"]\n\n[dependencies]\nsqlx-core = { workspace = true, features = [\"any\"] }\nsqlx-macros-core = { workspace = true }\n\nproc-macro2 = { version = \"1.0.36\", default-features = false }\nsyn = { version = \"2.0.52\", default-features = false, features = [\"parsing\", \"proc-macro\"] }\nquote = { version = \"1.0.26\", default-features = false }\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "sqlx-macros/src/lib.rs",
    "content": "use proc_macro::TokenStream;\n\nuse quote::quote;\n\nuse sqlx_macros_core::*;\n\n#[cfg(feature = \"macros\")]\n#[proc_macro]\npub fn expand_query(input: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(input as query::QueryMacroInput);\n\n    match query::expand_input(input, FOSS_DRIVERS) {\n        Ok(ts) => ts.into(),\n        Err(e) => {\n            if let Some(parse_err) = e.downcast_ref::<syn::Error>() {\n                parse_err.to_compile_error().into()\n            } else {\n                let msg = e.to_string();\n                quote!(::std::compile_error!(#msg)).into()\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"derive\")]\n#[proc_macro_derive(Encode, attributes(sqlx))]\npub fn derive_encode(tokenstream: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(tokenstream as syn::DeriveInput);\n    match derives::expand_derive_encode(&input) {\n        Ok(ts) => ts.into(),\n        Err(e) => e.to_compile_error().into(),\n    }\n}\n\n#[cfg(feature = \"derive\")]\n#[proc_macro_derive(Decode, attributes(sqlx))]\npub fn derive_decode(tokenstream: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(tokenstream as syn::DeriveInput);\n    match derives::expand_derive_decode(&input) {\n        Ok(ts) => ts.into(),\n        Err(e) => e.to_compile_error().into(),\n    }\n}\n\n#[cfg(feature = \"derive\")]\n#[proc_macro_derive(Type, attributes(sqlx))]\npub fn derive_type(tokenstream: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(tokenstream as syn::DeriveInput);\n    match derives::expand_derive_type_encode_decode(&input) {\n        Ok(ts) => ts.into(),\n        Err(e) => e.to_compile_error().into(),\n    }\n}\n\n#[cfg(feature = \"derive\")]\n#[proc_macro_derive(FromRow, attributes(sqlx))]\npub fn derive_from_row(input: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(input as syn::DeriveInput);\n\n    match derives::expand_derive_from_row(&input) {\n        Ok(ts) => ts.into(),\n        Err(e) => e.to_compile_error().into(),\n    }\n}\n\n#[cfg(feature = \"migrate\")]\n#[proc_macro]\npub fn migrate(input: TokenStream) -> TokenStream {\n    use syn::LitStr;\n\n    let input = syn::parse_macro_input!(input as Option<LitStr>);\n    match migrate::expand(input) {\n        Ok(ts) => ts.into(),\n        Err(e) => {\n            if let Some(parse_err) = e.downcast_ref::<syn::Error>() {\n                parse_err.to_compile_error().into()\n            } else {\n                let msg = e.to_string();\n                quote!(::std::compile_error!(#msg)).into()\n            }\n        }\n    }\n}\n\n#[cfg(feature = \"macros\")]\n#[proc_macro_attribute]\npub fn test(args: TokenStream, input: TokenStream) -> TokenStream {\n    let input = syn::parse_macro_input!(input as syn::ItemFn);\n\n    match test_attr::expand(args.into(), input) {\n        Ok(ts) => ts.into(),\n        Err(e) => {\n            if let Some(parse_err) = e.downcast_ref::<syn::Error>() {\n                parse_err.to_compile_error().into()\n            } else {\n                let msg = e.to_string();\n                quote!(::std::compile_error!(#msg)).into()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-macros-core/Cargo.toml",
    "content": "[package]\nname = \"sqlx-macros-core\"\ndescription = \"Macro support core for SQLx, the Rust SQL toolkit. Not intended to be used directly.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n[features]\ndefault = []\n\n# for conditional compilation\n_rt-async-global-executor = [\"async-global-executor\", \"sqlx-core/_rt-async-global-executor\"]\n_rt-async-std = [\"async-std\", \"sqlx-core/_rt-async-std\"]\n_rt-smol = [\"smol\", \"sqlx-core/_rt-smol\"]\n_rt-tokio = [\"tokio\", \"sqlx-core/_rt-tokio\"]\n\n_tls-native-tls = [\"sqlx-core/_tls-native-tls\"]\n_tls-rustls-aws-lc-rs = [\"sqlx-core/_tls-rustls-aws-lc-rs\"]\n_tls-rustls-ring-webpki = [\"sqlx-core/_tls-rustls-ring-webpki\"]\n_tls-rustls-ring-native-roots = [\"sqlx-core/_tls-rustls-ring-native-roots\"]\n\n_sqlite = []\n\n# SQLx features\nderive = []\nmacros = [\"thiserror\"]\nmigrate = [\"sqlx-core/migrate\"]\n\nsqlx-toml = [\"sqlx-core/sqlx-toml\", \"sqlx-sqlite?/sqlx-toml\"]\n\n# database\nmysql = [\"sqlx-mysql\"]\npostgres = [\"sqlx-postgres\"]\nsqlite = [\"_sqlite\", \"sqlx-sqlite/bundled\"]\nsqlite-unbundled = [\"_sqlite\", \"sqlx-sqlite/unbundled\"]\n\n# Enables `drivers.sqlite.unsafe-load-extensions` in sqlx.toml\nsqlite-load-extension = [\"sqlx-sqlite/load-extension\"]\n\n# type integrations\njson = [\"sqlx-core/json\", \"sqlx-mysql?/json\", \"sqlx-postgres?/json\", \"sqlx-sqlite?/json\"]\n\nbigdecimal = [\"sqlx-core/bigdecimal\", \"sqlx-mysql?/bigdecimal\", \"sqlx-postgres?/bigdecimal\"]\nbit-vec = [\"sqlx-core/bit-vec\", \"sqlx-postgres?/bit-vec\"]\nchrono = [\"sqlx-core/chrono\", \"sqlx-mysql?/chrono\", \"sqlx-postgres?/chrono\", \"sqlx-sqlite?/chrono\"]\nipnet = [\"sqlx-core/ipnet\", \"sqlx-postgres?/ipnet\"]\nipnetwork = [\"sqlx-core/ipnetwork\", \"sqlx-postgres?/ipnetwork\"]\nmac_address = [\"sqlx-core/mac_address\", \"sqlx-postgres?/mac_address\"]\nrust_decimal = [\"sqlx-core/rust_decimal\", \"sqlx-mysql?/rust_decimal\", \"sqlx-postgres?/rust_decimal\"]\ntime = [\"sqlx-core/time\", \"sqlx-mysql?/time\", \"sqlx-postgres?/time\", \"sqlx-sqlite?/time\"]\nuuid = [\"sqlx-core/uuid\", \"sqlx-mysql?/uuid\", \"sqlx-postgres?/uuid\", \"sqlx-sqlite?/uuid\"]\n\n[dependencies]\nsqlx-core = { workspace = true, features = [\"offline\"] }\nsqlx-mysql = { workspace = true, features = [\"offline\", \"migrate\"], optional = true }\nsqlx-postgres = { workspace = true, features = [\"offline\", \"migrate\"], optional = true }\nsqlx-sqlite = { workspace = true, features = [\"offline\", \"migrate\"], optional = true }\n\nasync-global-executor = { workspace = true, optional = true }\nasync-std = { workspace = true, optional = true }\nsmol = { workspace = true, optional = true }\ntokio = { workspace = true, optional = true }\n\ncfg-if = { workspace = true}\ndotenvy = { workspace = true }\nthiserror = { workspace = true, optional = true }\n\nhex = { version = \"0.4.3\" }\nheck = { version = \"0.5\" }\neither = \"1.6.1\"\nproc-macro2 = { version = \"1.0.79\", default-features = false }\nserde = { version = \"1.0.132\", features = [\"derive\"] }\nserde_json = { version = \"1.0.73\" }\nsha2 = { version = \"0.10.0\" }\nsyn = { version = \"2.0.52\", default-features = false, features = [\"full\", \"derive\", \"parsing\", \"printing\", \"clone-impls\"] }\nquote = { version = \"1.0.26\", default-features = false }\nurl = { version = \"2.2.2\" }\n\n[lints.rust.unexpected_cfgs]\nlevel = \"warn\"\ncheck-cfg = ['cfg(sqlx_macros_unstable)', 'cfg(procmacro2_semver_exempt)']\n"
  },
  {
    "path": "sqlx-macros-core/clippy.toml",
    "content": "[[disallowed-methods]]\npath = \"std::env::var\"\nreason = \"use `crate::env()` instead, which optionally calls `proc_macro::tracked_env::var()`\"\n"
  },
  {
    "path": "sqlx-macros-core/src/common.rs",
    "content": "use proc_macro2::Span;\nuse std::path::{Path, PathBuf};\n\npub(crate) fn resolve_path(path: impl AsRef<Path>, err_span: Span) -> syn::Result<PathBuf> {\n    let path = path.as_ref();\n\n    if path.is_absolute() {\n        return Err(syn::Error::new(\n            err_span,\n            \"absolute paths will only work on the current machine\",\n        ));\n    }\n\n    // requires `proc_macro::SourceFile::path()` to be stable\n    // https://github.com/rust-lang/rust/issues/54725\n    if path.is_relative()\n        && path\n            .parent()\n            .is_none_or(|parent| parent.as_os_str().is_empty())\n    {\n        return Err(syn::Error::new(\n            err_span,\n            \"paths relative to the current file's directory are not currently supported\",\n        ));\n    }\n\n    let mut out_path = crate::manifest_dir().map_err(|e| syn::Error::new(err_span, e))?;\n\n    out_path.push(path);\n\n    Ok(out_path)\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/database/impls.rs",
    "content": "macro_rules! impl_database_ext {\n    (\n        $database:path,\n        row: $row:path,\n        $(describe-blocking: $describe:path,)?\n    ) => {\n        impl $crate::database::DatabaseExt for $database {\n            const DATABASE_PATH: &'static str = stringify!($database);\n            const ROW_PATH: &'static str = stringify!($row);\n            impl_describe_blocking!($database, $($describe)?);\n        }\n    }\n}\n\nmacro_rules! impl_describe_blocking {\n    ($database:path $(,)?) => {\n        fn describe_blocking(\n            query: &str,\n            database_url: &str,\n            driver_config: &sqlx_core::config::drivers::Config,\n        ) -> sqlx_core::Result<sqlx_core::describe::Describe<Self>> {\n            use $crate::database::CachingDescribeBlocking;\n\n            // This can't be a provided method because the `static` can't reference `Self`.\n            static CACHE: CachingDescribeBlocking<$database> = CachingDescribeBlocking::new();\n\n            CACHE.describe(query, database_url, driver_config)\n        }\n    };\n    ($database:path, $describe:path) => {\n        fn describe_blocking(\n            query: &str,\n            database_url: &str,\n            driver_config: &sqlx_core::config::drivers::Config,\n        ) -> sqlx_core::Result<sqlx_core::describe::Describe<Self>> {\n            $describe(query, database_url, driver_config)\n        }\n    };\n}\n\n// The paths below will also be emitted from the macros, so they need to match the final facade.\nmod sqlx {\n    #[cfg(feature = \"mysql\")]\n    pub use sqlx_mysql as mysql;\n\n    #[cfg(feature = \"postgres\")]\n    pub use sqlx_postgres as postgres;\n\n    #[cfg(feature = \"_sqlite\")]\n    pub use sqlx_sqlite as sqlite;\n}\n\n// NOTE: type mappings have been moved to `src/type_checking.rs` in their respective driver crates.\n#[cfg(feature = \"mysql\")]\nimpl_database_ext! {\n    sqlx::mysql::MySql,\n    row: sqlx::mysql::MySqlRow,\n}\n\n#[cfg(feature = \"postgres\")]\nimpl_database_ext! {\n    sqlx::postgres::Postgres,\n    row: sqlx::postgres::PgRow,\n}\n\n#[cfg(feature = \"_sqlite\")]\nimpl_database_ext! {\n    sqlx::sqlite::Sqlite,\n    row: sqlx::sqlite::SqliteRow,\n    // Since proc-macros don't benefit from async, we can make a describe call directly\n    // which also ensures that the database is closed afterwards, regardless of errors.\n    describe-blocking: sqlx_sqlite::describe_blocking,\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/database/mod.rs",
    "content": "use sqlx_core::config;\nuse sqlx_core::connection::Connection;\nuse sqlx_core::database::Database;\nuse sqlx_core::describe::Describe;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse sqlx_core::sql_str::SqlSafeStr;\nuse sqlx_core::type_checking::TypeChecking;\nuse std::collections::hash_map;\nuse std::collections::HashMap;\nuse std::sync::{LazyLock, Mutex};\n\n#[cfg(any(feature = \"postgres\", feature = \"mysql\", feature = \"_sqlite\"))]\nmod impls;\n\npub trait DatabaseExt: Database + TypeChecking {\n    const DATABASE_PATH: &'static str;\n    const ROW_PATH: &'static str;\n\n    fn db_path() -> syn::Path {\n        syn::parse_str(Self::DATABASE_PATH).unwrap()\n    }\n\n    fn row_path() -> syn::Path {\n        syn::parse_str(Self::ROW_PATH).unwrap()\n    }\n\n    fn describe_blocking(\n        query: &str,\n        database_url: &str,\n        driver_config: &config::drivers::Config,\n    ) -> sqlx_core::Result<Describe<Self>>;\n}\n\n#[allow(dead_code)]\npub struct CachingDescribeBlocking<DB: DatabaseExt> {\n    connections: LazyLock<Mutex<HashMap<String, DB::Connection>>>,\n}\n\n#[allow(dead_code)]\nimpl<DB: DatabaseExt> CachingDescribeBlocking<DB> {\n    #[allow(clippy::new_without_default, reason = \"internal API\")]\n    pub const fn new() -> Self {\n        CachingDescribeBlocking {\n            connections: LazyLock::new(|| Mutex::new(HashMap::new())),\n        }\n    }\n\n    pub fn describe(\n        &self,\n        query: &str,\n        database_url: &str,\n        _driver_config: &config::drivers::Config,\n    ) -> sqlx_core::Result<Describe<DB>>\n    where\n        for<'a> &'a mut DB::Connection: Executor<'a, Database = DB>,\n    {\n        let mut cache = self\n            .connections\n            .lock()\n            .expect(\"previous panic in describe call\");\n\n        crate::block_on(async {\n            let conn = match cache.entry(database_url.to_string()) {\n                hash_map::Entry::Occupied(hit) => hit.into_mut(),\n                hash_map::Entry::Vacant(miss) => {\n                    let conn = miss.insert(DB::Connection::connect(database_url).await?);\n\n                    #[cfg(feature = \"postgres\")]\n                    if DB::NAME == sqlx_postgres::Postgres::NAME {\n                        conn.execute(\n                            \"\n                            DO $$\n                            BEGIN\n                                IF EXISTS (\n                                    SELECT 1\n                                    FROM pg_settings\n                                    WHERE name = 'plan_cache_mode'\n                                ) THEN\n                                    SET SESSION plan_cache_mode = 'force_generic_plan';\n                                END IF;\n                            END $$;\n                        \",\n                        )\n                        .await?;\n                    }\n                    conn\n                }\n            };\n\n            match conn\n                .describe(AssertSqlSafe(query.to_string()).into_sql_str())\n                .await\n            {\n                Ok(describe) => Ok(describe),\n                Err(e) => {\n                    if matches!(e, sqlx_core::Error::Io(_) | sqlx_core::Error::Protocol(_)) {\n                        cache.remove(database_url);\n                    }\n\n                    Err(e)\n                }\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/derives/attributes.rs",
    "content": "use proc_macro2::{Ident, Span, TokenStream};\nuse quote::quote_spanned;\nuse syn::{\n    parenthesized, punctuated::Punctuated, token::Comma, Attribute, DeriveInput, Field, LitStr,\n    Meta, Token, Type, Variant,\n};\n\nmacro_rules! assert_attribute {\n    ($e:expr, $err:expr, $input:expr) => {\n        if !$e {\n            return Err(syn::Error::new_spanned($input, $err));\n        }\n    };\n}\n\nmacro_rules! fail {\n    ($t:expr, $m:expr) => {\n        return Err(syn::Error::new_spanned($t, $m))\n    };\n}\n\nmacro_rules! try_set {\n    ($i:ident, $v:expr, $t:expr) => {\n        match $i {\n            None => $i = Some($v),\n            Some(_) => fail!($t, \"duplicate attribute\"),\n        }\n    };\n}\n\npub struct TypeName {\n    pub val: String,\n    pub span: Span,\n}\n\nimpl TypeName {\n    pub fn get(&self) -> TokenStream {\n        let val = &self.val;\n        quote_spanned! { self.span => #val }\n    }\n}\n\n#[derive(Copy, Clone)]\n#[allow(clippy::enum_variant_names)]\npub enum RenameAll {\n    LowerCase,\n    SnakeCase,\n    UpperCase,\n    ScreamingSnakeCase,\n    KebabCase,\n    CamelCase,\n    PascalCase,\n}\n\npub struct SqlxContainerAttributes {\n    pub transparent: bool,\n    pub type_name: Option<TypeName>,\n    pub rename_all: Option<RenameAll>,\n    pub repr: Option<Ident>,\n    pub no_pg_array: bool,\n    pub default: bool,\n}\n\npub enum JsonAttribute {\n    NonNullable,\n    Nullable,\n}\n\npub struct SqlxChildAttributes {\n    pub rename: Option<String>,\n    pub default: bool,\n    pub flatten: bool,\n    pub try_from: Option<Type>,\n    pub skip: bool,\n    pub json: Option<JsonAttribute>,\n}\n\npub fn parse_container_attributes(input: &[Attribute]) -> syn::Result<SqlxContainerAttributes> {\n    let mut transparent = None;\n    let mut repr = None;\n    let mut type_name = None;\n    let mut rename_all = None;\n    let mut no_pg_array = None;\n    let mut default = None;\n\n    for attr in input {\n        if attr.path().is_ident(\"sqlx\") {\n            attr.parse_nested_meta(|meta| {\n                if meta.path.is_ident(\"transparent\") {\n                    try_set!(transparent, true, attr);\n                } else if meta.path.is_ident(\"no_pg_array\") {\n                    try_set!(no_pg_array, true, attr);\n                } else if meta.path.is_ident(\"default\") {\n                    try_set!(default, true, attr);\n                } else if meta.path.is_ident(\"rename_all\") {\n                    meta.input.parse::<Token![=]>()?;\n                    let lit: LitStr = meta.input.parse()?;\n\n                    let val = match lit.value().as_str() {\n                        \"lowercase\" => RenameAll::LowerCase,\n                        \"snake_case\" => RenameAll::SnakeCase,\n                        \"UPPERCASE\" => RenameAll::UpperCase,\n                        \"SCREAMING_SNAKE_CASE\" => RenameAll::ScreamingSnakeCase,\n                        \"kebab-case\" => RenameAll::KebabCase,\n                        \"camelCase\" => RenameAll::CamelCase,\n                        \"PascalCase\" => RenameAll::PascalCase,\n                        _ => fail!(lit, \"unexpected value for rename_all\"),\n                    };\n\n                    try_set!(rename_all, val, lit)\n                } else if meta.path.is_ident(\"type_name\") {\n                    meta.input.parse::<Token![=]>()?;\n                    let lit: LitStr = meta.input.parse()?;\n                    let name = TypeName {\n                        val: lit.value(),\n                        span: lit.span(),\n                    };\n\n                    try_set!(type_name, name, lit)\n                } else {\n                    fail!(meta.path, \"unexpected attribute\")\n                }\n\n                Ok(())\n            })?;\n        } else if attr.path().is_ident(\"repr\") {\n            let list: Punctuated<Meta, Token![,]> =\n                attr.parse_args_with(<Punctuated<Meta, Token![,]>>::parse_terminated)?;\n\n            if let Some(path) = list.iter().find_map(|f| f.require_path_only().ok()) {\n                try_set!(repr, path.get_ident().unwrap().clone(), list);\n            }\n        }\n    }\n\n    Ok(SqlxContainerAttributes {\n        transparent: transparent.unwrap_or(false),\n        repr,\n        type_name,\n        rename_all,\n        no_pg_array: no_pg_array.unwrap_or(false),\n        default: default.unwrap_or(false),\n    })\n}\n\npub fn parse_child_attributes(input: &[Attribute]) -> syn::Result<SqlxChildAttributes> {\n    let mut rename = None;\n    let mut default = false;\n    let mut try_from = None;\n    let mut flatten = false;\n    let mut skip: bool = false;\n    let mut json = None;\n\n    for attr in input.iter().filter(|a| a.path().is_ident(\"sqlx\")) {\n        attr.parse_nested_meta(|meta| {\n            if meta.path.is_ident(\"rename\") {\n                meta.input.parse::<Token![=]>()?;\n                let val: LitStr = meta.input.parse()?;\n                try_set!(rename, val.value(), val);\n            } else if meta.path.is_ident(\"try_from\") {\n                meta.input.parse::<Token![=]>()?;\n                let val: LitStr = meta.input.parse()?;\n                try_set!(try_from, val.parse()?, val);\n            } else if meta.path.is_ident(\"default\") {\n                default = true;\n            } else if meta.path.is_ident(\"flatten\") {\n                flatten = true;\n            } else if meta.path.is_ident(\"skip\") {\n                skip = true;\n            } else if meta.path.is_ident(\"json\") {\n                if meta.input.peek(syn::token::Paren) {\n                    let content;\n                    parenthesized!(content in meta.input);\n                    let literal: Ident = content.parse()?;\n                    assert_eq!(literal.to_string(), \"nullable\", \"Unrecognized `json` attribute. Valid values are `json` or `json(nullable)`\");\n                    json = Some(JsonAttribute::Nullable);\n                } else {\n                    json = Some(JsonAttribute::NonNullable);\n                }\n            }\n\n            Ok(())\n        })?;\n\n        if json.is_some() && flatten {\n            fail!(\n                attr,\n                \"Cannot use `json` and `flatten` together on the same field\"\n            );\n        }\n    }\n\n    Ok(SqlxChildAttributes {\n        rename,\n        default,\n        flatten,\n        try_from,\n        skip,\n        json,\n    })\n}\n\npub fn check_transparent_attributes(\n    input: &DeriveInput,\n    field: &Field,\n) -> syn::Result<SqlxContainerAttributes> {\n    let attributes = parse_container_attributes(&input.attrs)?;\n\n    assert_attribute!(\n        attributes.rename_all.is_none(),\n        \"unexpected #[sqlx(rename_all = ..)]\",\n        field\n    );\n\n    let ch_attributes = parse_child_attributes(&field.attrs)?;\n\n    assert_attribute!(\n        ch_attributes.rename.is_none(),\n        \"unexpected #[sqlx(rename = ..)]\",\n        field\n    );\n\n    Ok(attributes)\n}\n\npub fn check_enum_attributes(input: &DeriveInput) -> syn::Result<SqlxContainerAttributes> {\n    let attributes = parse_container_attributes(&input.attrs)?;\n\n    assert_attribute!(\n        !attributes.transparent,\n        \"unexpected #[sqlx(transparent)]\",\n        input\n    );\n\n    Ok(attributes)\n}\n\npub fn check_weak_enum_attributes(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<SqlxContainerAttributes> {\n    let attributes = check_enum_attributes(input)?;\n\n    assert_attribute!(attributes.repr.is_some(), \"expected #[repr(..)]\", input);\n\n    assert_attribute!(\n        attributes.rename_all.is_none(),\n        \"unexpected #[sqlx(c = ..)]\",\n        input\n    );\n\n    for variant in variants {\n        let attributes = parse_child_attributes(&variant.attrs)?;\n\n        assert_attribute!(\n            attributes.rename.is_none(),\n            \"unexpected #[sqlx(rename = ..)]\",\n            variant\n        );\n    }\n\n    Ok(attributes)\n}\n\npub fn check_strong_enum_attributes(\n    input: &DeriveInput,\n    _variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<SqlxContainerAttributes> {\n    let attributes = check_enum_attributes(input)?;\n\n    assert_attribute!(attributes.repr.is_none(), \"unexpected #[repr(..)]\", input);\n\n    Ok(attributes)\n}\n\npub fn check_struct_attributes(\n    input: &DeriveInput,\n    fields: &Punctuated<Field, Comma>,\n) -> syn::Result<SqlxContainerAttributes> {\n    let attributes = parse_container_attributes(&input.attrs)?;\n\n    assert_attribute!(\n        !attributes.transparent,\n        \"#[sqlx(transparent)] is only valid for structs with exactly one field\",\n        input\n    );\n\n    assert_attribute!(\n        attributes.rename_all.is_none(),\n        \"unexpected #[sqlx(rename_all = ..)]\",\n        input\n    );\n\n    assert_attribute!(attributes.repr.is_none(), \"unexpected #[repr(..)]\", input);\n\n    for field in fields {\n        let attributes = parse_child_attributes(&field.attrs)?;\n\n        assert_attribute!(\n            attributes.rename.is_none(),\n            \"unexpected #[sqlx(rename = ..)]\",\n            field\n        );\n    }\n\n    Ok(attributes)\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/derives/decode.rs",
    "content": "use super::attributes::{\n    check_strong_enum_attributes, check_struct_attributes, check_transparent_attributes,\n    check_weak_enum_attributes, parse_child_attributes, parse_container_attributes,\n};\nuse super::rename_all;\nuse proc_macro2::TokenStream;\nuse quote::quote;\nuse syn::punctuated::Punctuated;\nuse syn::token::Comma;\nuse syn::{\n    parse_quote, Arm, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed, Stmt,\n    TypeParamBound, Variant,\n};\n\npub fn expand_derive_decode(input: &DeriveInput) -> syn::Result<TokenStream> {\n    let attrs = parse_container_attributes(&input.attrs)?;\n    match &input.data {\n        Data::Struct(DataStruct { fields, .. })\n            if fields.len() == 1 && (matches!(fields, Fields::Unnamed(_)) || attrs.transparent) =>\n        {\n            expand_derive_decode_transparent(input, fields.iter().next().unwrap())\n        }\n        Data::Enum(DataEnum { variants, .. }) => match attrs.repr {\n            Some(_) => expand_derive_decode_weak_enum(input, variants),\n            None => expand_derive_decode_strong_enum(input, variants),\n        },\n        Data::Struct(DataStruct {\n            fields: Fields::Named(FieldsNamed { named, .. }),\n            ..\n        }) => expand_derive_decode_struct(input, named),\n        Data::Union(_) => Err(syn::Error::new_spanned(input, \"unions are not supported\")),\n        Data::Struct(DataStruct {\n            fields: Fields::Unnamed(..),\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"tuple structs may only have a single field\",\n        )),\n        Data::Struct(DataStruct {\n            fields: Fields::Unit,\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"unit structs are not supported\",\n        )),\n    }\n}\n\nfn expand_derive_decode_transparent(\n    input: &DeriveInput,\n    field: &Field,\n) -> syn::Result<TokenStream> {\n    check_transparent_attributes(input, field)?;\n\n    let ident = &input.ident;\n    let ty = &field.ty;\n\n    // extract type generics\n    let generics = &input.generics;\n    let (_, ty_generics, _) = generics.split_for_impl();\n\n    // add db type for impl generics & where clause\n    let mut generics = generics.clone();\n    generics\n        .params\n        .insert(0, parse_quote!(DB: ::sqlx::Database));\n    generics.params.insert(0, parse_quote!('r));\n    generics\n        .make_where_clause()\n        .predicates\n        .push(parse_quote!(#ty: ::sqlx::decode::Decode<'r, DB>));\n    let (impl_generics, _, where_clause) = generics.split_for_impl();\n\n    let field_ident = if let Some(ident) = &field.ident {\n        quote! { #ident }\n    } else {\n        quote! { 0 }\n    };\n\n    let tts = quote!(\n        #[automatically_derived]\n        impl #impl_generics ::sqlx::decode::Decode<'r, DB> for #ident #ty_generics #where_clause {\n            fn decode(\n                value: <DB as ::sqlx::database::Database>::ValueRef<'r>,\n            ) -> ::std::result::Result<\n                Self,\n                ::std::boxed::Box<\n                    dyn ::std::error::Error + 'static + ::std::marker::Send + ::std::marker::Sync,\n                >,\n            > {\n                <#ty as ::sqlx::decode::Decode<'r, DB>>::decode(value)\n                    .map(|val| Self { #field_ident: val })\n            }\n        }\n    );\n\n    Ok(tts)\n}\n\nfn expand_derive_decode_weak_enum(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<TokenStream> {\n    let attr = check_weak_enum_attributes(input, variants)?;\n    let repr = attr.repr.unwrap();\n\n    let ident = &input.ident;\n    let ident_s = ident.to_string();\n\n    let arms = variants\n        .iter()\n        .map(|v| {\n            let id = &v.ident;\n            parse_quote! {\n                _ if (#ident::#id as #repr) == value => ::std::result::Result::Ok(#ident::#id),\n            }\n        })\n        .collect::<Vec<Arm>>();\n\n    Ok(quote!(\n        #[automatically_derived]\n        impl<'r, DB: ::sqlx::Database> ::sqlx::decode::Decode<'r, DB> for #ident\n        where\n            #repr: ::sqlx::decode::Decode<'r, DB>,\n        {\n            fn decode(\n                value: <DB as ::sqlx::database::Database>::ValueRef<'r>,\n            ) -> ::std::result::Result<\n                Self,\n                ::std::boxed::Box<\n                    dyn ::std::error::Error + 'static + ::std::marker::Send + ::std::marker::Sync,\n                >,\n            > {\n                let value = <#repr as ::sqlx::decode::Decode<'r, DB>>::decode(value)?;\n\n                match value {\n                    #(#arms)*\n                    _ => ::std::result::Result::Err(::std::boxed::Box::new(::sqlx::Error::Decode(\n                        ::std::format!(\"invalid value {:?} for enum {}\", value, #ident_s).into(),\n                    )))\n                }\n            }\n        }\n    ))\n}\n\nfn expand_derive_decode_strong_enum(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<TokenStream> {\n    let cattr = check_strong_enum_attributes(input, variants)?;\n\n    let ident = &input.ident;\n    let ident_s = ident.to_string();\n\n    let value_arms = variants.iter().map(|v| -> Arm {\n        let id = &v.ident;\n        let attributes = parse_child_attributes(&v.attrs).unwrap();\n\n        if let Some(rename) = attributes.rename {\n            parse_quote!(#rename => ::std::result::Result::Ok(#ident :: #id),)\n        } else if let Some(pattern) = cattr.rename_all {\n            let name = rename_all(&id.to_string(), pattern);\n\n            parse_quote!(#name => ::std::result::Result::Ok(#ident :: #id),)\n        } else {\n            let name = id.to_string();\n            parse_quote!(#name => ::std::result::Result::Ok(#ident :: #id),)\n        }\n    });\n\n    let values = quote! {\n        match value {\n            #(#value_arms)*\n\n            _ => Err(format!(\"invalid value {:?} for enum {}\", value, #ident_s).into())\n        }\n    };\n\n    let mut tts = TokenStream::new();\n\n    if cfg!(feature = \"mysql\") {\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl<'r> ::sqlx::decode::Decode<'r, ::sqlx::mysql::MySql> for #ident {\n                fn decode(\n                    value: ::sqlx::mysql::MySqlValueRef<'r>,\n                ) -> ::std::result::Result<\n                    Self,\n                    ::std::boxed::Box<\n                        dyn ::std::error::Error\n                            + 'static\n                            + ::std::marker::Send\n                            + ::std::marker::Sync,\n                    >,\n                > {\n                    let value = <&'r ::std::primitive::str as ::sqlx::decode::Decode<\n                        'r,\n                        ::sqlx::mysql::MySql,\n                    >>::decode(value)?;\n\n                    #values\n                }\n            }\n        ));\n    }\n\n    if cfg!(feature = \"postgres\") {\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl<'r> ::sqlx::decode::Decode<'r, ::sqlx::postgres::Postgres> for #ident {\n                fn decode(\n                    value: ::sqlx::postgres::PgValueRef<'r>,\n                ) -> ::std::result::Result<\n                    Self,\n                    ::std::boxed::Box<\n                        dyn ::std::error::Error\n                            + 'static\n                            + ::std::marker::Send\n                            + ::std::marker::Sync,\n                    >,\n                > {\n                    let value = <&'r ::std::primitive::str as ::sqlx::decode::Decode<\n                        'r,\n                        ::sqlx::postgres::Postgres,\n                    >>::decode(value)?;\n\n                    #values\n                }\n            }\n        ));\n    }\n\n    if cfg!(feature = \"_sqlite\") {\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl<'r> ::sqlx::decode::Decode<'r, ::sqlx::sqlite::Sqlite> for #ident {\n                fn decode(\n                    value: ::sqlx::sqlite::SqliteValueRef<'r>,\n                ) -> ::std::result::Result<\n                    Self,\n                    ::std::boxed::Box<\n                        dyn ::std::error::Error\n                            + 'static\n                            + ::std::marker::Send\n                            + ::std::marker::Sync,\n                    >,\n                > {\n                    let value = <&'r ::std::primitive::str as ::sqlx::decode::Decode<\n                        'r,\n                        ::sqlx::sqlite::Sqlite,\n                    >>::decode(value)?;\n\n                    #values\n                }\n            }\n        ));\n    }\n\n    Ok(tts)\n}\n\nfn expand_derive_decode_struct(\n    input: &DeriveInput,\n    fields: &Punctuated<Field, Comma>,\n) -> syn::Result<TokenStream> {\n    check_struct_attributes(input, fields)?;\n\n    let mut tts = TokenStream::new();\n\n    if cfg!(feature = \"postgres\") {\n        let ident = &input.ident;\n\n        let (_, ty_generics, where_clause) = input.generics.split_for_impl();\n\n        let mut generics = input.generics.clone();\n\n        // add db type for impl generics & where clause\n        for type_param in &mut generics.type_params_mut() {\n            type_param.bounds.extend::<[TypeParamBound; 2]>([\n                parse_quote!(for<'decode> ::sqlx::decode::Decode<'decode, ::sqlx::Postgres>),\n                parse_quote!(::sqlx::types::Type<::sqlx::Postgres>),\n            ]);\n        }\n\n        generics.params.push(parse_quote!('r));\n\n        let (impl_generics, _, _) = generics.split_for_impl();\n\n        let reads = fields.iter().map(|field| -> Stmt {\n            let id = &field.ident;\n            let ty = &field.ty;\n\n            parse_quote!(\n                let #id = decoder.try_decode::<#ty>()?;\n            )\n        });\n\n        let names = fields.iter().map(|field| &field.ident);\n\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl #impl_generics ::sqlx::decode::Decode<'r, ::sqlx::Postgres> for #ident #ty_generics\n            #where_clause\n            {\n                fn decode(\n                    value: ::sqlx::postgres::PgValueRef<'r>,\n                ) -> ::std::result::Result<\n                    Self,\n                    ::std::boxed::Box<\n                        dyn ::std::error::Error\n                            + 'static\n                            + ::std::marker::Send\n                            + ::std::marker::Sync,\n                    >,\n                > {\n                    let mut decoder = ::sqlx::postgres::types::PgRecordDecoder::new(value)?;\n\n                    #(#reads)*\n\n                    ::std::result::Result::Ok(#ident {\n                        #(#names),*\n                    })\n                }\n            }\n        ));\n    }\n\n    Ok(tts)\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/derives/encode.rs",
    "content": "use super::attributes::{\n    check_strong_enum_attributes, check_struct_attributes, check_transparent_attributes,\n    check_weak_enum_attributes, parse_child_attributes, parse_container_attributes,\n};\nuse super::rename_all;\nuse proc_macro2::{Span, TokenStream};\nuse quote::quote;\nuse syn::punctuated::Punctuated;\nuse syn::token::Comma;\nuse syn::{\n    parse_quote, Data, DataEnum, DataStruct, DeriveInput, Expr, Field, Fields, FieldsNamed,\n    Lifetime, LifetimeParam, Stmt, TypeParamBound, Variant,\n};\n\npub fn expand_derive_encode(input: &DeriveInput) -> syn::Result<TokenStream> {\n    let args = parse_container_attributes(&input.attrs)?;\n\n    match &input.data {\n        Data::Struct(DataStruct { fields, .. })\n            if fields.len() == 1 && (matches!(fields, Fields::Unnamed(_)) || args.transparent) =>\n        {\n            expand_derive_encode_transparent(input, fields.iter().next().unwrap())\n        }\n        Data::Enum(DataEnum { variants, .. }) => match args.repr {\n            Some(_) => expand_derive_encode_weak_enum(input, variants),\n            None => expand_derive_encode_strong_enum(input, variants),\n        },\n        Data::Struct(DataStruct {\n            fields: Fields::Named(FieldsNamed { named, .. }),\n            ..\n        }) => expand_derive_encode_struct(input, named),\n        Data::Union(_) => Err(syn::Error::new_spanned(input, \"unions are not supported\")),\n        Data::Struct(DataStruct {\n            fields: Fields::Unnamed(..),\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"tuple structs may only have a single field\",\n        )),\n        Data::Struct(DataStruct {\n            fields: Fields::Unit,\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"unit structs are not supported\",\n        )),\n    }\n}\n\nfn expand_derive_encode_transparent(\n    input: &DeriveInput,\n    field: &Field,\n) -> syn::Result<TokenStream> {\n    check_transparent_attributes(input, field)?;\n\n    let ident = &input.ident;\n    let ty = &field.ty;\n\n    // extract type generics\n    let generics = &input.generics;\n    let (_, ty_generics, _) = generics.split_for_impl();\n\n    // add db type for impl generics & where clause\n    let lifetime = Lifetime::new(\"'q\", Span::call_site());\n    let mut generics = generics.clone();\n    generics\n        .params\n        .insert(0, LifetimeParam::new(lifetime.clone()).into());\n\n    generics\n        .params\n        .insert(0, parse_quote!(DB: ::sqlx::Database));\n    generics\n        .make_where_clause()\n        .predicates\n        .push(parse_quote!(#ty: ::sqlx::encode::Encode<#lifetime, DB>));\n    let (impl_generics, _, where_clause) = generics.split_for_impl();\n\n    let field_ident = if let Some(ident) = &field.ident {\n        quote! { #ident }\n    } else {\n        quote! { 0 }\n    };\n\n    Ok(quote!(\n        #[automatically_derived]\n        impl #impl_generics ::sqlx::encode::Encode<#lifetime, DB> for #ident #ty_generics\n        #where_clause\n        {\n            fn encode_by_ref(\n                &self,\n                buf: &mut <DB as ::sqlx::database::Database>::ArgumentBuffer,\n            ) -> ::std::result::Result<::sqlx::encode::IsNull, ::sqlx::error::BoxDynError> {\n                <#ty as ::sqlx::encode::Encode<#lifetime, DB>>::encode_by_ref(&self.#field_ident, buf)\n            }\n\n            fn produces(&self) -> Option<DB::TypeInfo> {\n                <#ty as ::sqlx::encode::Encode<#lifetime, DB>>::produces(&self.#field_ident)\n            }\n\n            fn size_hint(&self) -> usize {\n                <#ty as ::sqlx::encode::Encode<#lifetime, DB>>::size_hint(&self.#field_ident)\n            }\n        }\n    ))\n}\n\nfn expand_derive_encode_weak_enum(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<TokenStream> {\n    let attr = check_weak_enum_attributes(input, variants)?;\n    let repr = attr.repr.unwrap();\n    let ident = &input.ident;\n\n    let mut values = Vec::new();\n\n    for v in variants {\n        let id = &v.ident;\n        values.push(quote!(#ident :: #id => (#ident :: #id as #repr),));\n    }\n\n    Ok(quote!(\n        #[automatically_derived]\n        impl<'q, DB: ::sqlx::Database> ::sqlx::encode::Encode<'q, DB> for #ident\n        where\n            #repr: ::sqlx::encode::Encode<'q, DB>,\n        {\n            fn encode_by_ref(\n                &self,\n                buf: &mut <DB as ::sqlx::database::Database>::ArgumentBuffer,\n            ) -> ::std::result::Result<::sqlx::encode::IsNull, ::sqlx::error::BoxDynError> {\n                let value = match self {\n                    #(#values)*\n                };\n\n                <#repr as ::sqlx::encode::Encode<DB>>::encode_by_ref(&value, buf)\n            }\n\n            fn size_hint(&self) -> usize {\n                <#repr as ::sqlx::encode::Encode<DB>>::size_hint(&Default::default())\n            }\n        }\n    ))\n}\n\nfn expand_derive_encode_strong_enum(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<TokenStream> {\n    let cattr = check_strong_enum_attributes(input, variants)?;\n\n    let ident = &input.ident;\n\n    let mut value_arms = Vec::new();\n\n    for v in variants {\n        let id = &v.ident;\n        let attributes = parse_child_attributes(&v.attrs)?;\n\n        if let Some(rename) = attributes.rename {\n            value_arms.push(quote!(#ident :: #id => #rename,));\n        } else if let Some(pattern) = cattr.rename_all {\n            let name = rename_all(&id.to_string(), pattern);\n\n            value_arms.push(quote!(#ident :: #id => #name,));\n        } else {\n            let name = id.to_string();\n            value_arms.push(quote!(#ident :: #id => #name,));\n        }\n    }\n\n    Ok(quote!(\n        #[automatically_derived]\n        impl<'q, DB: ::sqlx::Database> ::sqlx::encode::Encode<'q, DB> for #ident\n        where\n            &'q ::std::primitive::str: ::sqlx::encode::Encode<'q, DB>,\n        {\n            fn encode_by_ref(\n                &self,\n                buf: &mut <DB as ::sqlx::database::Database>::ArgumentBuffer,\n            ) -> ::std::result::Result<::sqlx::encode::IsNull, ::sqlx::error::BoxDynError> {\n                let val = match self {\n                    #(#value_arms)*\n                };\n\n                <&::std::primitive::str as ::sqlx::encode::Encode<'q, DB>>::encode(val, buf)\n            }\n\n            fn size_hint(&self) -> ::std::primitive::usize {\n                let val = match self {\n                    #(#value_arms)*\n                };\n\n                <&::std::primitive::str as ::sqlx::encode::Encode<'q, DB>>::size_hint(&val)\n            }\n        }\n    ))\n}\n\nfn expand_derive_encode_struct(\n    input: &DeriveInput,\n    fields: &Punctuated<Field, Comma>,\n) -> syn::Result<TokenStream> {\n    check_struct_attributes(input, fields)?;\n\n    let mut tts = TokenStream::new();\n\n    if cfg!(feature = \"postgres\") {\n        let ident = &input.ident;\n        let column_count = fields.len();\n\n        let (_, ty_generics, where_clause) = input.generics.split_for_impl();\n\n        let mut generics = input.generics.clone();\n\n        // add db type for impl generics & where clause\n        for type_param in &mut generics.type_params_mut() {\n            type_param.bounds.extend::<[TypeParamBound; 2]>([\n                parse_quote!(for<'encode> ::sqlx::encode::Encode<'encode, ::sqlx::Postgres>),\n                parse_quote!(::sqlx::types::Type<::sqlx::Postgres>),\n            ]);\n        }\n\n        generics.params.push(parse_quote!('q));\n\n        let (impl_generics, _, _) = generics.split_for_impl();\n\n        let writes = fields.iter().map(|field| -> Stmt {\n            let id = &field.ident;\n\n            parse_quote!(\n                encoder.encode(&self. #id)?;\n            )\n        });\n\n        let sizes = fields.iter().map(|field| -> Expr {\n            let id = &field.ident;\n            let ty = &field.ty;\n\n            parse_quote!(\n                <#ty as ::sqlx::encode::Encode<::sqlx::Postgres>>::size_hint(&self. #id)\n            )\n        });\n\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl #impl_generics ::sqlx::encode::Encode<'_, ::sqlx::Postgres> for #ident #ty_generics\n            #where_clause\n            {\n                fn encode_by_ref(\n                    &self,\n                    buf: &mut ::sqlx::postgres::PgArgumentBuffer,\n                ) -> ::std::result::Result<::sqlx::encode::IsNull, ::sqlx::error::BoxDynError> {\n                    let mut encoder = ::sqlx::postgres::types::PgRecordEncoder::new(buf);\n\n                    #(#writes)*\n\n                    encoder.finish();\n\n                    ::std::result::Result::Ok(::sqlx::encode::IsNull::No)\n                }\n\n                fn size_hint(&self) -> ::std::primitive::usize {\n                    #column_count * (4 + 4) // oid (int) and length (int) for each column\n                        + #(#sizes)+* // sum of the size hints for each column\n                }\n            }\n        ));\n    }\n\n    Ok(tts)\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/derives/mod.rs",
    "content": "mod attributes;\nmod decode;\nmod encode;\nmod row;\nmod r#type;\n\npub use decode::expand_derive_decode;\npub use encode::expand_derive_encode;\npub use r#type::expand_derive_type;\npub use row::expand_derive_from_row;\n\nuse self::attributes::RenameAll;\nuse heck::{ToKebabCase, ToLowerCamelCase, ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase};\nuse proc_macro2::TokenStream;\nuse syn::DeriveInput;\n\npub fn expand_derive_type_encode_decode(input: &DeriveInput) -> syn::Result<TokenStream> {\n    let encode_tts = expand_derive_encode(input)?;\n    let decode_tts = expand_derive_decode(input)?;\n    let type_tts = expand_derive_type(input)?;\n\n    let combined = TokenStream::from_iter(encode_tts.into_iter().chain(decode_tts).chain(type_tts));\n\n    Ok(combined)\n}\n\npub(crate) fn rename_all(s: &str, pattern: RenameAll) -> String {\n    match pattern {\n        RenameAll::LowerCase => s.to_lowercase(),\n        RenameAll::SnakeCase => s.to_snake_case(),\n        RenameAll::UpperCase => s.to_uppercase(),\n        RenameAll::ScreamingSnakeCase => s.to_shouty_snake_case(),\n        RenameAll::KebabCase => s.to_kebab_case(),\n        RenameAll::CamelCase => s.to_lower_camel_case(),\n        RenameAll::PascalCase => s.to_upper_camel_case(),\n    }\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/derives/row.rs",
    "content": "use proc_macro2::{Span, TokenStream};\nuse quote::quote;\nuse syn::{\n    parse_quote, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Expr, Field,\n    Fields, FieldsNamed, FieldsUnnamed, Lifetime, Stmt,\n};\n\nuse super::{\n    attributes::{parse_child_attributes, parse_container_attributes, JsonAttribute},\n    rename_all,\n};\n\npub fn expand_derive_from_row(input: &DeriveInput) -> syn::Result<TokenStream> {\n    match &input.data {\n        Data::Struct(DataStruct {\n            fields: Fields::Named(FieldsNamed { named, .. }),\n            ..\n        }) => expand_derive_from_row_struct(input, named),\n\n        Data::Struct(DataStruct {\n            fields: Fields::Unnamed(FieldsUnnamed { unnamed, .. }),\n            ..\n        }) => expand_derive_from_row_struct_unnamed(input, unnamed),\n\n        Data::Struct(DataStruct {\n            fields: Fields::Unit,\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"unit structs are not supported\",\n        )),\n\n        Data::Enum(_) => Err(syn::Error::new_spanned(input, \"enums are not supported\")),\n\n        Data::Union(_) => Err(syn::Error::new_spanned(input, \"unions are not supported\")),\n    }\n}\n\nfn expand_derive_from_row_struct(\n    input: &DeriveInput,\n    fields: &Punctuated<Field, Comma>,\n) -> syn::Result<TokenStream> {\n    let ident = &input.ident;\n\n    let generics = &input.generics;\n\n    let (lifetime, provided) = generics\n        .lifetimes()\n        .next()\n        .map(|def| (def.lifetime.clone(), false))\n        .unwrap_or_else(|| (Lifetime::new(\"'a\", Span::call_site()), true));\n\n    let (_, ty_generics, _) = generics.split_for_impl();\n\n    let mut generics = generics.clone();\n    generics.params.insert(0, parse_quote!(R: ::sqlx::Row));\n\n    if provided {\n        generics.params.insert(0, parse_quote!(#lifetime));\n    }\n\n    let predicates = &mut generics.make_where_clause().predicates;\n\n    predicates.push(parse_quote!(&#lifetime ::std::primitive::str: ::sqlx::ColumnIndex<R>));\n\n    let container_attributes = parse_container_attributes(&input.attrs)?;\n\n    let default_instance: Option<Stmt> = if container_attributes.default {\n        predicates.push(parse_quote!(#ident: ::std::default::Default));\n        Some(parse_quote!(\n            let __default = #ident::default();\n        ))\n    } else {\n        None\n    };\n\n    let reads: Vec<Stmt> = fields\n        .iter()\n        .filter_map(|field| -> Option<Stmt> {\n            let id = &field.ident.as_ref()?;\n            let attributes = parse_child_attributes(&field.attrs).unwrap();\n            let ty = &field.ty;\n\n            if attributes.skip {\n                return Some(parse_quote!(\n                    let #id: #ty = Default::default();\n                ));\n            }\n\n            let id_s = if let Some(s) = attributes.rename {\n                s\n            } else {\n                let s = id.to_string().trim_start_matches(\"r#\").to_owned();\n                match container_attributes.rename_all {\n                    Some(pattern) => rename_all(&s, pattern),\n                    None => s\n                }\n            };\n\n            let expr: Expr = match (attributes.flatten, attributes.try_from, attributes.json) {\n                // <No attributes>\n                (false, None, None) => {\n                    predicates\n                        .push(parse_quote!(#ty: ::sqlx::decode::Decode<#lifetime, R::Database>));\n                    predicates.push(parse_quote!(#ty: ::sqlx::types::Type<R::Database>));\n\n                    parse_quote!(__row.try_get(#id_s))\n                }\n                // Flatten\n                (true, None, None) => {\n                    predicates.push(parse_quote!(#ty: ::sqlx::FromRow<#lifetime, R>));\n                    parse_quote!(<#ty as ::sqlx::FromRow<#lifetime, R>>::from_row(__row))\n                }\n                // Flatten + Try from\n                (true, Some(try_from), None) => {\n                    predicates.push(parse_quote!(#try_from: ::sqlx::FromRow<#lifetime, R>));\n                    parse_quote!(\n                        <#try_from as ::sqlx::FromRow<#lifetime, R>>::from_row(__row)\n                            .and_then(|v| {\n                                <#ty as ::std::convert::TryFrom::<#try_from>>::try_from(v)\n                                    .map_err(|e| {\n                                        // Triggers a lint warning if `TryFrom::Err = Infallible`\n                                        #[allow(unreachable_code)]\n                                        ::sqlx::Error::ColumnDecode {\n                                            index: #id_s.to_string(),\n                                            source: sqlx::__spec_error!(e),\n                                        }\n                                    })\n                            })\n                    )\n                }\n                // Flatten + Json\n                (true, _, Some(_)) => {\n                    panic!(\"Cannot use both flatten and json\")\n                }\n                // Try from\n                (false, Some(try_from), None) => {\n                    predicates\n                        .push(parse_quote!(#try_from: ::sqlx::decode::Decode<#lifetime, R::Database>));\n                    predicates.push(parse_quote!(#try_from: ::sqlx::types::Type<R::Database>)); \n\n                    parse_quote!(\n                        __row.try_get(#id_s)\n                            .and_then(|v| {\n                                <#ty as ::std::convert::TryFrom::<#try_from>>::try_from(v)\n                                    .map_err(|e| {\n                                        // Triggers a lint warning if `TryFrom::Err = Infallible`\n                                        #[allow(unreachable_code)]\n                                        ::sqlx::Error::ColumnDecode {\n                                            index: #id_s.to_string(),\n                                            source: sqlx::__spec_error!(e),\n                                        }\n                                    })\n                            })\n                    )\n                }\n                // Try from + Json mandatory\n                (false, Some(try_from), Some(JsonAttribute::NonNullable)) => {\n                    predicates\n                        .push(parse_quote!(::sqlx::types::Json<#try_from>: ::sqlx::decode::Decode<#lifetime, R::Database>));\n                    predicates.push(parse_quote!(::sqlx::types::Json<#try_from>: ::sqlx::types::Type<R::Database>));\n\n                    parse_quote!(\n                        __row.try_get::<::sqlx::types::Json<_>, _>(#id_s)\n                            .and_then(|v| {\n                                <#ty as ::std::convert::TryFrom::<#try_from>>::try_from(v.0)\n                                    .map_err(|e| {\n                                        // Triggers a lint warning if `TryFrom::Err = Infallible`\n                                        #[allow(unreachable_code)]\n                                        ::sqlx::Error::ColumnDecode {\n                                            index: #id_s.to_string(),\n                                            source: sqlx::__spec_error!(e),\n                                        }\n                                    })\n                            })\n                    )\n                },\n                // Try from + Json nullable\n                (false, Some(_), Some(JsonAttribute::Nullable)) => {\n                    panic!(\"Cannot use both try from and json nullable\")\n                },\n                // Json\n                (false, None, Some(JsonAttribute::NonNullable)) => {\n                    predicates\n                        .push(parse_quote!(::sqlx::types::Json<#ty>: ::sqlx::decode::Decode<#lifetime, R::Database>));\n                    predicates.push(parse_quote!(::sqlx::types::Json<#ty>: ::sqlx::types::Type<R::Database>));\n\n                    parse_quote!(__row.try_get::<::sqlx::types::Json<_>, _>(#id_s).map(|x| x.0))\n                },\n                (false, None, Some(JsonAttribute::Nullable)) => {\n                    predicates\n                        .push(parse_quote!(::core::option::Option<::sqlx::types::Json<#ty>>: ::sqlx::decode::Decode<#lifetime, R::Database>));\n                    predicates.push(parse_quote!(::core::option::Option<::sqlx::types::Json<#ty>>: ::sqlx::types::Type<R::Database>));\n\n                    parse_quote!(__row.try_get::<::core::option::Option<::sqlx::types::Json<_>>, _>(#id_s).map(|x| x.and_then(|y| y.0)))\n                },\n            };\n\n            if attributes.default {\n                Some(parse_quote!(\n                    let #id: #ty = #expr.or_else(|e| match e {\n                        ::sqlx::Error::ColumnNotFound(_) => {\n                            ::std::result::Result::Ok(Default::default())\n                        },\n                        e => ::std::result::Result::Err(e)\n                    })?;\n                ))\n            } else if container_attributes.default {\n                Some(parse_quote!(\n                    let #id: #ty = #expr.or_else(|e| match e {\n                        ::sqlx::Error::ColumnNotFound(_) => {\n                            ::std::result::Result::Ok(__default.#id)\n                        },\n                        e => ::std::result::Result::Err(e)\n                    })?;\n                ))\n            } else {\n                Some(parse_quote!(\n                    let #id: #ty = #expr?;\n                ))\n            }\n        })\n        .collect();\n\n    let (impl_generics, _, where_clause) = generics.split_for_impl();\n\n    let names = fields.iter().map(|field| &field.ident);\n\n    Ok(quote!(\n        #[automatically_derived]\n        impl #impl_generics ::sqlx::FromRow<#lifetime, R> for #ident #ty_generics #where_clause {\n            fn from_row(__row: &#lifetime R) -> ::sqlx::Result<Self> {\n                #default_instance\n\n                #(#reads)*\n\n                ::std::result::Result::Ok(#ident {\n                    #(#names),*\n                })\n            }\n        }\n    ))\n}\n\nfn expand_derive_from_row_struct_unnamed(\n    input: &DeriveInput,\n    fields: &Punctuated<Field, Comma>,\n) -> syn::Result<TokenStream> {\n    let ident = &input.ident;\n\n    let generics = &input.generics;\n\n    let (lifetime, provided) = generics\n        .lifetimes()\n        .next()\n        .map(|def| (def.lifetime.clone(), false))\n        .unwrap_or_else(|| (Lifetime::new(\"'a\", Span::call_site()), true));\n\n    let (_, ty_generics, _) = generics.split_for_impl();\n\n    let mut generics = generics.clone();\n    generics.params.insert(0, parse_quote!(R: ::sqlx::Row));\n\n    if provided {\n        generics.params.insert(0, parse_quote!(#lifetime));\n    }\n\n    let predicates = &mut generics.make_where_clause().predicates;\n\n    predicates.push(parse_quote!(\n        ::std::primitive::usize: ::sqlx::ColumnIndex<R>\n    ));\n\n    for field in fields {\n        let ty = &field.ty;\n\n        predicates.push(parse_quote!(#ty: ::sqlx::decode::Decode<#lifetime, R::Database>));\n        predicates.push(parse_quote!(#ty: ::sqlx::types::Type<R::Database>));\n    }\n\n    let (impl_generics, _, where_clause) = generics.split_for_impl();\n\n    let gets = fields\n        .iter()\n        .enumerate()\n        .map(|(idx, _)| quote!(row.try_get(#idx)?));\n\n    Ok(quote!(\n        #[automatically_derived]\n        impl #impl_generics ::sqlx::FromRow<#lifetime, R> for #ident #ty_generics #where_clause {\n            fn from_row(row: &#lifetime R) -> ::sqlx::Result<Self> {\n                ::std::result::Result::Ok(#ident (\n                    #(#gets),*\n                ))\n            }\n        }\n    ))\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/derives/type.rs",
    "content": "use super::attributes::{\n    check_strong_enum_attributes, check_struct_attributes, check_transparent_attributes,\n    check_weak_enum_attributes, parse_container_attributes, TypeName,\n};\nuse proc_macro2::{Ident, TokenStream};\nuse quote::{quote, quote_spanned};\nuse syn::punctuated::Punctuated;\nuse syn::token::Comma;\nuse syn::{\n    parse_quote, Data, DataEnum, DataStruct, DeriveInput, Field, Fields, FieldsNamed, Variant,\n};\n\npub fn expand_derive_type(input: &DeriveInput) -> syn::Result<TokenStream> {\n    let attrs = parse_container_attributes(&input.attrs)?;\n    match &input.data {\n        // Newtype structs:\n        // struct Foo(i32);\n        // struct Foo { field: i32 };\n        Data::Struct(DataStruct { fields, .. })\n            if fields.len() == 1 && (matches!(fields, Fields::Unnamed(_)) || attrs.transparent) =>\n        {\n            expand_derive_has_sql_type_transparent(input, fields.iter().next().unwrap())\n        }\n        // Record types\n        // struct Foo { foo: i32, bar: String }\n        Data::Struct(DataStruct {\n            fields: Fields::Named(FieldsNamed { named, .. }),\n            ..\n        }) => expand_derive_has_sql_type_struct(input, named),\n        Data::Struct(DataStruct {\n            fields: Fields::Unnamed(..),\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"tuple structs may only have a single field\",\n        )),\n        Data::Struct(DataStruct {\n            fields: Fields::Unit,\n            ..\n        }) => Err(syn::Error::new_spanned(\n            input,\n            \"unit structs are not supported\",\n        )),\n\n        Data::Enum(DataEnum { variants, .. }) => match attrs.repr {\n            // Enums that encode to/from integers (weak enums)\n            Some(_) => expand_derive_has_sql_type_weak_enum(input, variants),\n            // Enums that decode to/from strings (strong enums)\n            None => expand_derive_has_sql_type_strong_enum(input, variants),\n        },\n        Data::Union(_) => Err(syn::Error::new_spanned(input, \"unions are not supported\")),\n    }\n}\n\nfn expand_derive_has_sql_type_transparent(\n    input: &DeriveInput,\n    field: &Field,\n) -> syn::Result<TokenStream> {\n    let attr = check_transparent_attributes(input, field)?;\n\n    let ident = &input.ident;\n    let ty = &field.ty;\n\n    let generics = &input.generics;\n    let (_, ty_generics, _) = generics.split_for_impl();\n\n    if attr.transparent {\n        let mut generics = generics.clone();\n        let mut array_generics = generics.clone();\n\n        generics\n            .params\n            .insert(0, parse_quote!(DB: ::sqlx::Database));\n        generics\n            .make_where_clause()\n            .predicates\n            .push(parse_quote!(#ty: ::sqlx::Type<DB>));\n        let (impl_generics, _, where_clause) = generics.split_for_impl();\n\n        array_generics\n            .make_where_clause()\n            .predicates\n            .push(parse_quote!(#ty: ::sqlx::postgres::PgHasArrayType));\n        let (array_impl_generics, _, array_where_clause) = array_generics.split_for_impl();\n\n        let mut tokens = quote!(\n            #[automatically_derived]\n            impl #impl_generics ::sqlx::Type< DB > for #ident #ty_generics #where_clause {\n                fn type_info() -> DB::TypeInfo {\n                    <#ty as ::sqlx::Type<DB>>::type_info()\n                }\n\n                fn compatible(ty: &DB::TypeInfo) -> ::std::primitive::bool {\n                    <#ty as ::sqlx::Type<DB>>::compatible(ty)\n                }\n            }\n        );\n\n        if cfg!(feature = \"postgres\") && !attr.no_pg_array {\n            tokens.extend(quote!(\n                #[automatically_derived]\n                impl #array_impl_generics ::sqlx::postgres::PgHasArrayType for #ident #ty_generics\n                #array_where_clause {\n                    fn array_type_info() -> ::sqlx::postgres::PgTypeInfo {\n                        <#ty as ::sqlx::postgres::PgHasArrayType>::array_type_info()\n                    }\n                }\n            ));\n        }\n\n        return Ok(tokens);\n    }\n\n    let mut tts = TokenStream::new();\n\n    if cfg!(feature = \"postgres\") {\n        let ty_name = type_name(ident, attr.type_name.as_ref());\n\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl ::sqlx::Type<::sqlx::postgres::Postgres> for #ident #ty_generics {\n                fn type_info() -> ::sqlx::postgres::PgTypeInfo {\n                    ::sqlx::postgres::PgTypeInfo::with_name(#ty_name)\n                }\n            }\n        ));\n\n        if !attr.no_pg_array {\n            tts.extend(quote!(\n                #[automatically_derived]\n                impl ::sqlx::postgres::PgHasArrayType for #ident #ty_generics {\n                    fn array_type_info() -> ::sqlx::postgres::PgTypeInfo {\n                        ::sqlx::postgres::PgTypeInfo::array_of(#ty_name)\n                    }\n                }\n            ));\n        }\n    }\n\n    Ok(tts)\n}\n\nfn expand_derive_has_sql_type_weak_enum(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<TokenStream> {\n    let attrs = check_weak_enum_attributes(input, variants)?;\n    let repr = attrs.repr.unwrap();\n    let ident = &input.ident;\n    let mut ts = quote!(\n        #[automatically_derived]\n        impl<DB: ::sqlx::Database> ::sqlx::Type<DB> for #ident\n        where\n            #repr: ::sqlx::Type<DB>,\n        {\n            fn type_info() -> DB::TypeInfo {\n                <#repr as ::sqlx::Type<DB>>::type_info()\n            }\n\n            fn compatible(ty: &DB::TypeInfo) -> bool {\n                <#repr as ::sqlx::Type<DB>>::compatible(ty)\n            }\n        }\n    );\n\n    if cfg!(feature = \"postgres\") && !attrs.no_pg_array {\n        ts.extend(quote!(\n            #[automatically_derived]\n            impl ::sqlx::postgres::PgHasArrayType for #ident  {\n                fn array_type_info() -> ::sqlx::postgres::PgTypeInfo {\n                    <#repr as ::sqlx::postgres::PgHasArrayType>::array_type_info()\n                }\n            }\n        ));\n    }\n\n    Ok(ts)\n}\n\nfn expand_derive_has_sql_type_strong_enum(\n    input: &DeriveInput,\n    variants: &Punctuated<Variant, Comma>,\n) -> syn::Result<TokenStream> {\n    let attributes = check_strong_enum_attributes(input, variants)?;\n\n    let ident = &input.ident;\n    let mut tts = TokenStream::new();\n\n    if cfg!(feature = \"mysql\") {\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl ::sqlx::Type<::sqlx::MySql> for #ident {\n                fn type_info() -> ::sqlx::mysql::MySqlTypeInfo {\n                    ::sqlx::mysql::MySqlTypeInfo::__enum()\n                }\n            }\n        ));\n    }\n\n    if cfg!(feature = \"postgres\") {\n        let ty_name = type_name(ident, attributes.type_name.as_ref());\n\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl ::sqlx::Type<::sqlx::Postgres> for #ident {\n                fn type_info() -> ::sqlx::postgres::PgTypeInfo {\n                    ::sqlx::postgres::PgTypeInfo::with_name(#ty_name)\n                }\n            }\n        ));\n\n        if !attributes.no_pg_array {\n            tts.extend(quote!(\n                #[automatically_derived]\n                impl ::sqlx::postgres::PgHasArrayType for #ident  {\n                    fn array_type_info() -> ::sqlx::postgres::PgTypeInfo {\n                        ::sqlx::postgres::PgTypeInfo::array_of(#ty_name)\n                    }\n                }\n            ));\n        }\n    }\n\n    if cfg!(feature = \"_sqlite\") {\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl sqlx::Type<::sqlx::Sqlite> for #ident {\n                fn type_info() -> ::sqlx::sqlite::SqliteTypeInfo {\n                    <::std::primitive::str as ::sqlx::Type<sqlx::Sqlite>>::type_info()\n                }\n\n                fn compatible(ty: &::sqlx::sqlite::SqliteTypeInfo) -> ::std::primitive::bool {\n                    <&::std::primitive::str as ::sqlx::types::Type<sqlx::sqlite::Sqlite>>::compatible(ty)\n                }\n            }\n        ));\n    }\n\n    Ok(tts)\n}\n\nfn expand_derive_has_sql_type_struct(\n    input: &DeriveInput,\n    fields: &Punctuated<Field, Comma>,\n) -> syn::Result<TokenStream> {\n    let attributes = check_struct_attributes(input, fields)?;\n\n    let ident = &input.ident;\n    let mut tts = TokenStream::new();\n\n    if cfg!(feature = \"postgres\") {\n        let ty_name = type_name(ident, attributes.type_name.as_ref());\n\n        tts.extend(quote!(\n            #[automatically_derived]\n            impl ::sqlx::Type<::sqlx::Postgres> for #ident {\n                fn type_info() -> ::sqlx::postgres::PgTypeInfo {\n                    ::sqlx::postgres::PgTypeInfo::with_name(#ty_name)\n                }\n            }\n        ));\n\n        if !attributes.no_pg_array {\n            tts.extend(quote!(\n                #[automatically_derived]\n                impl ::sqlx::postgres::PgHasArrayType for #ident  {\n                    fn array_type_info() -> ::sqlx::postgres::PgTypeInfo {\n                        ::sqlx::postgres::PgTypeInfo::array_of(#ty_name)\n                    }\n                }\n            ));\n        }\n    }\n\n    Ok(tts)\n}\n\nfn type_name(ident: &Ident, explicit_name: Option<&TypeName>) -> TokenStream {\n    explicit_name.map(|tn| tn.get()).unwrap_or_else(|| {\n        let s = ident.to_string();\n        quote_spanned!(ident.span()=> #s)\n    })\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/lib.rs",
    "content": "//! Support crate for SQLx's proc macros.\n//!\n//! ### Note: Semver Exempt API\n//! The API of this crate is not meant for general use and does *not* follow Semantic Versioning.\n//! The only crate that follows Semantic Versioning in the project is the `sqlx` crate itself.\n//! If you are building a custom SQLx driver, you should pin an exact version of this and\n//! `sqlx-core` to avoid breakages:\n//!\n//! ```toml\n//! sqlx-core = \"=0.6.2\"\n//! sqlx-macros-core = \"=0.6.2\"\n//! ```\n//!\n//! And then make releases in lockstep with `sqlx-core`. We recommend all driver crates, in-tree\n//! or otherwise, use the same version numbers as `sqlx-core` to avoid confusion.\n\n#![cfg_attr(\n    any(sqlx_macros_unstable, procmacro2_semver_exempt),\n    feature(track_path)\n)]\n\nuse cfg_if::cfg_if;\nuse std::path::PathBuf;\n\n#[cfg(feature = \"macros\")]\nuse crate::query::QueryDriver;\n\npub type Error = Box<dyn std::error::Error>;\n\npub type Result<T, E = Error> = std::result::Result<T, E>;\n\nmod common;\npub mod database;\n\n#[cfg(feature = \"derive\")]\npub mod derives;\n#[cfg(feature = \"macros\")]\npub mod query;\n\n#[cfg(feature = \"macros\")]\n// The compiler gives misleading help messages about `#[cfg(test)]` when this is just named `test`.\npub mod test_attr;\n\n#[cfg(feature = \"migrate\")]\npub mod migrate;\n\n#[cfg(feature = \"macros\")]\npub const FOSS_DRIVERS: &[QueryDriver] = &[\n    #[cfg(feature = \"mysql\")]\n    QueryDriver::new::<sqlx_mysql::MySql>(),\n    #[cfg(feature = \"postgres\")]\n    QueryDriver::new::<sqlx_postgres::Postgres>(),\n    #[cfg(feature = \"_sqlite\")]\n    QueryDriver::new::<sqlx_sqlite::Sqlite>(),\n];\n\npub fn block_on<F>(f: F) -> F::Output\nwhere\n    F: std::future::Future,\n{\n    cfg_if! {\n        if #[cfg(feature = \"_rt-async-global-executor\")] {\n            sqlx_core::rt::test_block_on(f)\n        } else if #[cfg(feature = \"_rt-async-std\")] {\n            async_std::task::block_on(f)\n        } else if #[cfg(feature = \"_rt-smol\")] {\n            sqlx_core::rt::test_block_on(f)\n        } else if #[cfg(feature = \"_rt-tokio\")] {\n            use std::sync::LazyLock;\n\n            use tokio::runtime::{self, Runtime};\n\n            // We need a single, persistent Tokio runtime since we're caching connections,\n            // otherwise we'll get \"IO driver has terminated\" errors.\n            static TOKIO_RT: LazyLock<Runtime> = LazyLock::new(|| {\n                runtime::Builder::new_current_thread()\n                    .enable_all()\n                    .build()\n                    .expect(\"failed to start Tokio runtime\")\n            });\n\n            TOKIO_RT.block_on(f)\n        } else {\n            sqlx_core::rt::missing_rt(f)\n        }\n    }\n}\n\npub fn env(var: &str) -> Result<String> {\n    env_opt(var)?\n        .ok_or_else(|| format!(\"env var {var:?} must be set to use the query macros\").into())\n}\n\n#[allow(clippy::disallowed_methods)]\npub fn env_opt(var: &str) -> Result<Option<String>> {\n    use std::env::VarError;\n\n    #[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]\n    let res: Result<String, VarError> = proc_macro::tracked_env::var(var);\n\n    #[cfg(not(any(sqlx_macros_unstable, procmacro2_semver_exempt)))]\n    let res: Result<String, VarError> = std::env::var(var);\n\n    match res {\n        Ok(val) => Ok(Some(val)),\n        Err(VarError::NotPresent) => Ok(None),\n        Err(VarError::NotUnicode(_)) => Err(format!(\"env var {var:?} is not valid UTF-8\").into()),\n    }\n}\n\npub fn manifest_dir() -> Result<PathBuf> {\n    Ok(env(\"CARGO_MANIFEST_DIR\")?.into())\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/migrate.rs",
    "content": "#[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]\nextern crate proc_macro;\n\nuse std::path::{Path, PathBuf};\n\nuse proc_macro2::{Span, TokenStream};\nuse quote::{quote, ToTokens, TokenStreamExt};\nuse sqlx_core::config::Config;\nuse sqlx_core::migrate::{Migration, MigrationType};\nuse syn::LitStr;\n\npub const DEFAULT_PATH: &str = \"./migrations\";\n\npub struct QuoteMigrationType(MigrationType);\n\nimpl ToTokens for QuoteMigrationType {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let ts = match self.0 {\n            MigrationType::Simple => quote! { ::sqlx::migrate::MigrationType::Simple },\n            MigrationType::ReversibleUp => quote! { ::sqlx::migrate::MigrationType::ReversibleUp },\n            MigrationType::ReversibleDown => {\n                quote! { ::sqlx::migrate::MigrationType::ReversibleDown }\n            }\n        };\n        tokens.append_all(ts);\n    }\n}\n\nstruct QuoteMigration {\n    migration: Migration,\n    path: PathBuf,\n}\n\nimpl ToTokens for QuoteMigration {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        let Migration {\n            version,\n            description,\n            migration_type,\n            checksum,\n            no_tx,\n            ..\n        } = &self.migration;\n\n        let migration_type = QuoteMigrationType(*migration_type);\n\n        let sql = self\n            .path\n            .canonicalize()\n            .map_err(|e| {\n                format!(\n                    \"error canonicalizing migration path {}: {e}\",\n                    self.path.display()\n                )\n            })\n            .and_then(|path| {\n                let path_str = path.to_str().ok_or_else(|| {\n                    format!(\n                        \"migration path cannot be represented as a string: {}\",\n                        self.path.display()\n                    )\n                })?;\n\n                // this tells the compiler to watch this path for changes\n                Ok(quote! { include_str!(#path_str) })\n            })\n            .unwrap_or_else(|e| quote! { compile_error!(#e) });\n\n        let ts = quote! {\n            ::sqlx::migrate::Migration {\n                version: #version,\n                description: ::std::borrow::Cow::Borrowed(#description),\n                migration_type:  #migration_type,\n                sql: ::sqlx::SqlStr::from_static(#sql),\n                no_tx: #no_tx,\n                checksum: ::std::borrow::Cow::Borrowed(&[\n                    #(#checksum),*\n                ]),\n            }\n        };\n\n        tokens.append_all(ts);\n    }\n}\n\npub fn default_path(config: &Config) -> &str {\n    config\n        .migrate\n        .migrations_dir\n        .as_deref()\n        .unwrap_or(DEFAULT_PATH)\n}\n\npub fn expand(path_arg: Option<LitStr>) -> crate::Result<TokenStream> {\n    let config = Config::try_from_crate_or_default()?;\n\n    let path = match path_arg {\n        Some(path_arg) => crate::common::resolve_path(path_arg.value(), path_arg.span())?,\n        None => { crate::common::resolve_path(default_path(&config), Span::call_site()) }?,\n    };\n\n    expand_with_path(&config, &path)\n}\n\npub fn expand_with_path(config: &Config, path: &Path) -> crate::Result<TokenStream> {\n    let path = path.canonicalize().map_err(|e| {\n        format!(\n            \"error canonicalizing migration directory {}: {e}\",\n            path.display()\n        )\n    })?;\n\n    let resolve_config = config.migrate.to_resolve_config();\n\n    // Use the same code path to resolve migrations at compile time and runtime.\n    let migrations = sqlx_core::migrate::resolve_blocking_with_config(&path, &resolve_config)?\n        .into_iter()\n        .map(|(migration, path)| QuoteMigration { migration, path });\n\n    let table_name = config.migrate.table_name();\n\n    let create_schemas = config.migrate.create_schemas.iter().map(|schema_name| {\n        quote! { ::std::borrow::Cow::Borrowed(#schema_name) }\n    });\n\n    #[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]\n    {\n        let path = path.to_str().ok_or_else(|| {\n            format!(\n                \"migration directory path cannot be represented as a string: {:?}\",\n                path\n            )\n        })?;\n\n        proc_macro::tracked_path::path(path);\n    }\n\n    Ok(quote! {\n        ::sqlx::migrate::Migrator {\n            migrations: ::std::borrow::Cow::Borrowed(const {&[\n                    #(#migrations),*\n            ]}),\n            create_schemas: ::std::borrow::Cow::Borrowed(&[#(#create_schemas),*]),\n            table_name: ::std::borrow::Cow::Borrowed(#table_name),\n            ..::sqlx::migrate::Migrator::DEFAULT\n        }\n    })\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/args.rs",
    "content": "use crate::database::DatabaseExt;\nuse crate::query::{QueryMacroInput, Warnings};\nuse either::Either;\nuse proc_macro2::TokenStream;\nuse quote::{format_ident, quote, quote_spanned};\nuse sqlx_core::config::Config;\nuse sqlx_core::describe::Describe;\nuse sqlx_core::type_checking;\nuse sqlx_core::type_info::TypeInfo;\nuse syn::spanned::Spanned;\nuse syn::{Expr, ExprCast, ExprGroup, Type};\n\n/// Returns a tokenstream which typechecks the arguments passed to the macro\n/// and binds them to `DB::Arguments` with the ident `query_args`.\npub fn quote_args<DB: DatabaseExt>(\n    input: &QueryMacroInput,\n    config: &Config,\n    warnings: &mut Warnings,\n    info: &Describe<DB>,\n) -> crate::Result<TokenStream> {\n    let db_path = DB::db_path();\n\n    if input.arg_exprs.is_empty() {\n        return Ok(quote! {\n            let query_args = ::core::result::Result::<_, ::sqlx::error::BoxDynError>::Ok(<#db_path as ::sqlx::database::Database>::Arguments::default());\n        });\n    }\n\n    let arg_names = (0..input.arg_exprs.len())\n        .map(|i| format_ident!(\"arg{}\", i))\n        .collect::<Vec<_>>();\n\n    let arg_name = &arg_names;\n    let arg_expr = input.arg_exprs.iter().cloned().map(strip_wildcard);\n\n    let arg_bindings = quote! {\n        #(let #arg_name = &(#arg_expr);)*\n    };\n\n    let args_check = match info.parameters() {\n        None | Some(Either::Right(_)) => {\n            // all we can do is check arity which we did\n            TokenStream::new()\n        }\n\n        Some(Either::Left(_)) if !input.checked => {\n            // this is an `*_unchecked!()` macro invocation\n            TokenStream::new()\n        }\n\n        Some(Either::Left(params)) => {\n            params\n                .iter()\n                .zip(arg_names.iter().zip(&input.arg_exprs))\n                .enumerate()\n                .map(|(i, (param_ty, (name, expr)))| -> crate::Result<_> {\n                    if get_type_override(expr).is_some() {\n                        // cast will fail to compile if the type does not match\n                        // and we strip casts to wildcard\n                        return Ok(quote!());\n                    }\n\n                    let param_ty = get_param_type::<DB>(param_ty, config, warnings, i)?;\n\n                    Ok(quote_spanned!(expr.span() =>\n                        // this shouldn't actually run\n                        #[allow(clippy::missing_panics_doc, clippy::unreachable)]\n                        if false {\n                            use ::sqlx::ty_match::{WrapSameExt as _, MatchBorrowExt as _};\n\n                            // evaluate the expression only once in case it contains moves\n                            let expr = ::sqlx::ty_match::dupe_value(#name);\n\n                            // if `expr` is `Option<T>`, get `Option<$ty>`, otherwise `$ty`\n                            let ty_check = ::sqlx::ty_match::WrapSame::<#param_ty, _>::new(&expr).wrap_same();\n\n                            // if `expr` is `&str`, convert `String` to `&str`\n                            let (mut _ty_check, match_borrow) = ::sqlx::ty_match::MatchBorrow::new(ty_check, &expr);\n\n                            _ty_check = match_borrow.match_borrow();\n\n                            // this causes move-analysis to effectively ignore this block\n                            ::std::unreachable!();\n                        }\n                    ))\n                })\n                .collect::<crate::Result<TokenStream>>()?\n        }\n    };\n\n    let args_count = input.arg_exprs.len();\n\n    Ok(quote! {\n        #arg_bindings\n\n        #args_check\n\n        let mut query_args = <#db_path as ::sqlx::database::Database>::Arguments::default();\n        query_args.reserve(\n            #args_count,\n            0 #(+ ::sqlx::encode::Encode::<#db_path>::size_hint(#arg_name))*\n        );\n        let query_args = ::core::result::Result::<_, ::sqlx::error::BoxDynError>::Ok(query_args)\n        #(.and_then(move |mut query_args| query_args.add(#arg_name).map(move |()| query_args) ))*;\n    })\n}\n\nfn get_param_type<DB: DatabaseExt>(\n    param_ty: &DB::TypeInfo,\n    config: &Config,\n    warnings: &mut Warnings,\n    i: usize,\n) -> crate::Result<TokenStream> {\n    if let Some(type_override) = config.macros.type_override(param_ty.name()) {\n        return Ok(type_override.parse()?);\n    }\n\n    let err = match DB::param_type_for_id(param_ty, &config.macros.preferred_crates) {\n        Ok(t) => return Ok(t.parse()?),\n        Err(e) => e,\n    };\n\n    let param_num = i + 1;\n\n    let message = match err {\n        type_checking::Error::NoMappingFound => {\n            if let Some(feature_gate) = DB::get_feature_gate(param_ty) {\n                format!(\n                    \"optional sqlx feature `{feature_gate}` required for type {param_ty} of param #{param_num}\",\n                )\n            } else {\n                format!(\n                    \"no built-in mapping for type {param_ty} of param #{param_num}; \\\n                         a type override may be required, see documentation for details\"\n                )\n            }\n        }\n        type_checking::Error::DateTimeCrateFeatureNotEnabled => {\n            let feature_gate = config\n                .macros\n                .preferred_crates\n                .date_time\n                .crate_name()\n                .expect(\"BUG: got feature-not-enabled error for DateTimeCrate::Inferred\");\n\n            format!(\n                \"SQLx feature `{feature_gate}` required for type {param_ty} of param #{param_num} \\\n                 (configured by `macros.preferred-crates.date-time` in sqlx.toml)\",\n            )\n        }\n        type_checking::Error::NumericCrateFeatureNotEnabled => {\n            let feature_gate = config\n                .macros\n                .preferred_crates\n                .numeric\n                .crate_name()\n                .expect(\"BUG: got feature-not-enabled error for NumericCrate::Inferred\");\n\n            format!(\n                \"SQLx feature `{feature_gate}` required for type {param_ty} of param #{param_num} \\\n                 (configured by `macros.preferred-crates.numeric` in sqlx.toml)\",\n            )\n        }\n\n        type_checking::Error::AmbiguousDateTimeType { fallback } => {\n            warnings.ambiguous_datetime = true;\n            return Ok(fallback.parse()?);\n        }\n\n        type_checking::Error::AmbiguousNumericType { fallback } => {\n            warnings.ambiguous_numeric = true;\n            return Ok(fallback.parse()?);\n        }\n    };\n\n    Err(message.into())\n}\n\nfn get_type_override(expr: &Expr) -> Option<&Type> {\n    match expr {\n        Expr::Group(group) => get_type_override(&group.expr),\n        Expr::Cast(cast) => Some(&cast.ty),\n        _ => None,\n    }\n}\n\nfn strip_wildcard(expr: Expr) -> Expr {\n    match expr {\n        Expr::Group(ExprGroup {\n            attrs,\n            group_token,\n            expr,\n        }) => Expr::Group(ExprGroup {\n            attrs,\n            group_token,\n            expr: Box::new(strip_wildcard(*expr)),\n        }),\n        // we want to retain casts if they semantically matter\n        Expr::Cast(ExprCast {\n            attrs,\n            expr,\n            as_token,\n            ty,\n        }) => match *ty {\n            // cast to wildcard `_` will produce weird errors; we interpret it as taking the value as-is\n            Type::Infer(_) => *expr,\n            _ => Expr::Cast(ExprCast {\n                attrs,\n                expr,\n                as_token,\n                ty,\n            }),\n        },\n        _ => expr,\n    }\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/cache.rs",
    "content": "use std::path::{Path, PathBuf};\nuse std::sync::Mutex;\nuse std::time::SystemTime;\n\n/// A cached value derived from one or more files, which is automatically invalidated\n/// if the modified-time of any watched file changes.\npub struct MtimeCache<T> {\n    inner: Mutex<Option<MtimeCacheInner<T>>>,\n}\n\npub struct MtimeCacheBuilder {\n    file_mtimes: Vec<(PathBuf, Option<SystemTime>)>,\n}\n\nstruct MtimeCacheInner<T> {\n    builder: MtimeCacheBuilder,\n    cached: T,\n}\n\nimpl<T: Clone> MtimeCache<T> {\n    pub fn new() -> Self {\n        MtimeCache {\n            inner: Mutex::new(None),\n        }\n    }\n\n    /// Get the cached value, or (re)initialize it if it does not exist or a file's mtime has changed.\n    pub fn get_or_try_init<E>(\n        &self,\n        init: impl FnOnce(&mut MtimeCacheBuilder) -> Result<T, E>,\n    ) -> Result<T, E> {\n        let mut inner = self.inner.lock().unwrap_or_else(|e| {\n            // Reset the cache on-panic.\n            let mut locked = e.into_inner();\n            *locked = None;\n            locked\n        });\n\n        if let Some(inner) = &*inner {\n            if !inner.builder.any_modified() {\n                return Ok(inner.cached.clone());\n            }\n        }\n\n        let mut builder = MtimeCacheBuilder::new();\n\n        let value = init(&mut builder)?;\n\n        *inner = Some(MtimeCacheInner {\n            builder,\n            cached: value.clone(),\n        });\n\n        Ok(value)\n    }\n}\n\nimpl MtimeCacheBuilder {\n    fn new() -> Self {\n        MtimeCacheBuilder {\n            file_mtimes: Vec::new(),\n        }\n    }\n\n    /// Add a file path to watch.\n    ///\n    /// The cached value will be automatically invalidated if the modified-time of the file changes,\n    /// or if the file does not exist but is created sometime after this call.\n    pub fn add_path(&mut self, path: PathBuf) {\n        let mtime = get_mtime(&path);\n\n        #[cfg(any(sqlx_macros_unstable, procmacro2_semver_exempt))]\n        {\n            proc_macro::tracked_path::path(&path);\n        }\n\n        self.file_mtimes.push((path, mtime));\n    }\n\n    fn any_modified(&self) -> bool {\n        for (path, expected_mtime) in &self.file_mtimes {\n            let actual_mtime = get_mtime(path);\n\n            if expected_mtime != &actual_mtime {\n                return true;\n            }\n        }\n\n        false\n    }\n}\n\nfn get_mtime(path: &Path) -> Option<SystemTime> {\n    std::fs::metadata(path)\n        .and_then(|metadata| metadata.modified())\n        .ok()\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/data.rs",
    "content": "use std::fmt::{Debug, Display, Formatter};\nuse std::fs;\nuse std::io::Write as _;\nuse std::marker::PhantomData;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, LazyLock, Mutex};\n\nuse serde::{Serialize, Serializer};\n\nuse sqlx_core::database::Database;\nuse sqlx_core::describe::Describe;\nuse sqlx_core::HashMap;\n\nuse crate::database::DatabaseExt;\nuse crate::query::cache::MtimeCache;\n\n#[derive(serde::Serialize)]\n#[serde(bound(serialize = \"Describe<DB>: serde::Serialize\"))]\n#[derive(Debug)]\npub struct QueryData<DB: Database> {\n    db_name: SerializeDbName<DB>,\n    #[allow(dead_code)]\n    pub(super) query: String,\n    pub(super) describe: Describe<DB>,\n    pub(super) hash: String,\n}\n\nimpl<DB: Database> QueryData<DB> {\n    pub fn from_describe(query: &str, describe: Describe<DB>) -> Self {\n        QueryData {\n            db_name: SerializeDbName::default(),\n            query: query.into(),\n            describe,\n            hash: hash_string(query),\n        }\n    }\n}\n\nstruct SerializeDbName<DB>(PhantomData<DB>);\n\nimpl<DB> Default for SerializeDbName<DB> {\n    fn default() -> Self {\n        SerializeDbName(PhantomData)\n    }\n}\n\nimpl<DB: Database> Debug for SerializeDbName<DB> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.debug_tuple(\"SerializeDbName\").field(&DB::NAME).finish()\n    }\n}\n\nimpl<DB: Database> Display for SerializeDbName<DB> {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        f.pad(DB::NAME)\n    }\n}\n\nimpl<DB: Database> Serialize for SerializeDbName<DB> {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(DB::NAME)\n    }\n}\n\nstatic OFFLINE_DATA_CACHE: LazyLock<Mutex<HashMap<PathBuf, Arc<MtimeCache<DynQueryData>>>>> =\n    LazyLock::new(Default::default);\n\n/// Offline query data\n#[derive(Clone, serde::Deserialize)]\npub struct DynQueryData {\n    pub db_name: String,\n    pub query: String,\n    pub describe: serde_json::Value,\n    pub hash: String,\n}\n\nimpl DynQueryData {\n    /// Loads a query given the path to its \"query-<hash>.json\" file. Subsequent calls for the same\n    /// path are retrieved from an in-memory cache.\n    pub fn from_data_file(path: &Path, query: &str) -> crate::Result<Self> {\n        let cache = OFFLINE_DATA_CACHE\n            .lock()\n            // Just reset the cache on error\n            .unwrap_or_else(|poison_err| {\n                let mut guard = poison_err.into_inner();\n                *guard = Default::default();\n                guard\n            })\n            .entry_ref(path)\n            .or_insert_with(|| Arc::new(MtimeCache::new()))\n            .clone();\n\n        cache.get_or_try_init(|builder| {\n            builder.add_path(path.into());\n\n            let offline_data_contents = fs::read_to_string(path).map_err(|e| {\n                format!(\"failed to read saved query path {}: {}\", path.display(), e)\n            })?;\n            let dyn_data: DynQueryData = serde_json::from_str(&offline_data_contents)?;\n\n            if query != dyn_data.query {\n                return Err(\"hash collision for saved query data\".into());\n            }\n\n            Ok(dyn_data)\n        })\n    }\n}\n\nimpl<DB: DatabaseExt> QueryData<DB>\nwhere\n    Describe<DB>: serde::Serialize + serde::de::DeserializeOwned,\n{\n    pub fn from_dyn_data(dyn_data: DynQueryData) -> crate::Result<Self> {\n        assert!(!dyn_data.db_name.is_empty());\n        assert!(!dyn_data.hash.is_empty());\n\n        if DB::NAME == dyn_data.db_name {\n            let describe: Describe<DB> = serde_json::from_value(dyn_data.describe)?;\n            Ok(QueryData {\n                db_name: SerializeDbName::default(),\n                query: dyn_data.query,\n                describe,\n                hash: dyn_data.hash,\n            })\n        } else {\n            Err(format!(\n                \"expected query data for {}, got data for {}\",\n                DB::NAME,\n                dyn_data.db_name\n            )\n            .into())\n        }\n    }\n\n    pub(super) fn save_in(&self, dir: &Path) -> crate::Result<()> {\n        use std::io::ErrorKind;\n\n        let path = dir.join(format!(\"query-{}.json\", self.hash));\n\n        if let Err(err) = fs::remove_file(&path) {\n            match err.kind() {\n                ErrorKind::NotFound | ErrorKind::PermissionDenied => (),\n                ErrorKind::NotADirectory => {\n                    return Err(format!(\n                        \"sqlx offline path exists, but is not a directory: {dir:?}\"\n                    )\n                    .into());\n                }\n                _ => return Err(format!(\"failed to delete {path:?}: {err:?}\").into()),\n            }\n        }\n\n        // Prevent tearing from concurrent invocations possibly trying to write the same file\n        // by using the existence of the file itself as a mutex.\n        //\n        // By deleting the file first and then using `.create_new(true)`,\n        // we guarantee that this only succeeds if another invocation hasn't concurrently\n        // re-created the file.\n        let mut file = match fs::OpenOptions::new()\n            .write(true)\n            .create_new(true)\n            .open(&path)\n        {\n            Ok(file) => file,\n            Err(err) => {\n                return match err.kind() {\n                    // We overlapped with a concurrent invocation and the other one succeeded.\n                    ErrorKind::AlreadyExists => Ok(()),\n                    ErrorKind::NotFound => {\n                        Err(format!(\"sqlx offline path does not exist: {dir:?}\").into())\n                    }\n                    ErrorKind::NotADirectory => Err(format!(\n                        \"sqlx offline path exists, but is not a directory: {dir:?}\"\n                    )\n                    .into()),\n                    _ => Err(format!(\"failed to exclusively create {path:?}: {err:?}\").into()),\n                };\n            }\n        };\n\n        // From a quick survey of the files generated by `examples/postgres/axum-social-with-tests`,\n        // which are generally in the 1-2 KiB range, this seems like a safe bet to avoid\n        // lots of reallocations without using too much memory.\n        //\n        // As of writing, `serde_json::to_vec_pretty()` only allocates 128 bytes up-front.\n        let mut data = Vec::with_capacity(4096);\n\n        serde_json::to_writer_pretty(&mut data, self).expect(\"BUG: failed to serialize query data\");\n\n        // Ensure there is a newline at the end of the JSON file to avoid\n        // accidental modification by IDE and make github diff tool happier.\n        data.push(b'\\n');\n\n        // This ideally writes the data in as few syscalls as possible.\n        file.write_all(&data)\n            .map_err(|err| format!(\"failed to write query data to file {path:?}: {err:?}\"))?;\n\n        // We don't really need to call `.sync_data()` since it's trivial to re-run the macro\n        // in the event a power loss results in incomplete flushing of the data to disk.\n\n        Ok(())\n    }\n}\n\npub(super) fn hash_string(query: &str) -> String {\n    // picked `sha2` because it's already in the dependency tree for both MySQL and Postgres\n    use sha2::{Digest, Sha256};\n\n    hex::encode(Sha256::digest(query.as_bytes()))\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/input.rs",
    "content": "use std::fs;\n\nuse proc_macro2::{Ident, Span};\nuse syn::parse::{Parse, ParseStream};\nuse syn::punctuated::Punctuated;\nuse syn::{Expr, LitBool, LitStr, Token};\nuse syn::{ExprArray, Type};\n\n/// Macro input shared by `query!()` and `query_file!()`\npub struct QueryMacroInput {\n    pub(super) sql: String,\n\n    pub(super) src_span: Span,\n\n    pub(super) record_type: RecordType,\n\n    pub(super) arg_exprs: Vec<Expr>,\n\n    pub(super) checked: bool,\n\n    pub(super) file_path: Option<String>,\n}\n\nenum QuerySrc {\n    String(String),\n    File(String),\n}\n\npub enum RecordType {\n    Given(Type),\n    Scalar,\n    Generated,\n}\n\nimpl Parse for QueryMacroInput {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let mut query_src: Option<(QuerySrc, Span)> = None;\n        let mut args: Option<Vec<Expr>> = None;\n        let mut record_type = RecordType::Generated;\n        let mut checked = true;\n\n        let mut expect_comma = false;\n\n        while !input.is_empty() {\n            if expect_comma {\n                let _ = input.parse::<syn::token::Comma>()?;\n            }\n\n            let key: Ident = input.parse()?;\n\n            let _ = input.parse::<syn::token::Eq>()?;\n\n            if key == \"source\" {\n                let span = input.span();\n                let query_str = Punctuated::<LitStr, Token![+]>::parse_separated_nonempty(input)?\n                    .iter()\n                    .map(LitStr::value)\n                    .collect();\n                query_src = Some((QuerySrc::String(query_str), span));\n            } else if key == \"source_file\" {\n                let lit_str = input.parse::<LitStr>()?;\n                query_src = Some((QuerySrc::File(lit_str.value()), lit_str.span()));\n            } else if key == \"args\" {\n                let exprs = input.parse::<ExprArray>()?;\n                args = Some(exprs.elems.into_iter().collect())\n            } else if key == \"record\" {\n                if !matches!(record_type, RecordType::Generated) {\n                    return Err(input.error(\"colliding `scalar` or `record` key\"));\n                }\n\n                record_type = RecordType::Given(input.parse()?);\n            } else if key == \"scalar\" {\n                if !matches!(record_type, RecordType::Generated) {\n                    return Err(input.error(\"colliding `scalar` or `record` key\"));\n                }\n\n                // we currently expect only `scalar = _`\n                // a `query_as_scalar!()` variant seems less useful than just overriding the type\n                // of the column in SQL\n                input.parse::<syn::Token![_]>()?;\n                record_type = RecordType::Scalar;\n            } else if key == \"checked\" {\n                let lit_bool = input.parse::<LitBool>()?;\n                checked = lit_bool.value;\n            } else {\n                let message = format!(\"unexpected input key: {key}\");\n                return Err(syn::Error::new_spanned(key, message));\n            }\n\n            expect_comma = true;\n        }\n\n        let (src, src_span) =\n            query_src.ok_or_else(|| input.error(\"expected `source` or `source_file` key\"))?;\n\n        let arg_exprs = args.unwrap_or_default();\n\n        let file_path = src.file_path(src_span)?;\n\n        Ok(QueryMacroInput {\n            sql: src.resolve(src_span)?,\n            src_span,\n            record_type,\n            arg_exprs,\n            checked,\n            file_path,\n        })\n    }\n}\n\nimpl QuerySrc {\n    /// If the query source is a file, read it to a string. Otherwise return the query string.\n    fn resolve(self, source_span: Span) -> syn::Result<String> {\n        match self {\n            QuerySrc::String(string) => Ok(string),\n            QuerySrc::File(file) => read_file_src(&file, source_span),\n        }\n    }\n\n    fn file_path(&self, source_span: Span) -> syn::Result<Option<String>> {\n        if let QuerySrc::File(ref file) = *self {\n            let path = crate::common::resolve_path(file, source_span)?\n                .canonicalize()\n                .map_err(|e| syn::Error::new(source_span, e))?;\n\n            Ok(Some(\n                path.to_str()\n                    .ok_or_else(|| {\n                        syn::Error::new(\n                            source_span,\n                            \"query file path cannot be represented as a string\",\n                        )\n                    })?\n                    .to_string(),\n            ))\n        } else {\n            Ok(None)\n        }\n    }\n}\n\nfn read_file_src(source: &str, source_span: Span) -> syn::Result<String> {\n    let file_path = crate::common::resolve_path(source, source_span)?;\n\n    fs::read_to_string(&file_path).map_err(|e| {\n        syn::Error::new(\n            source_span,\n            format!(\n                \"failed to read query file at {}: {}\",\n                file_path.display(),\n                e\n            ),\n        )\n    })\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/metadata.rs",
    "content": "use sqlx_core::config::Config;\nuse std::hash::{BuildHasherDefault, DefaultHasher};\nuse std::io;\nuse std::path::{Path, PathBuf};\nuse std::sync::{Arc, Mutex};\n\nuse crate::query::cache::{MtimeCache, MtimeCacheBuilder};\nuse sqlx_core::HashMap;\n\npub struct Metadata {\n    pub manifest_dir: PathBuf,\n    pub config: Config,\n    env: MtimeCache<Arc<MacrosEnv>>,\n    workspace_root: Arc<Mutex<Option<PathBuf>>>,\n}\n\npub struct MacrosEnv {\n    pub database_url: Option<String>,\n    pub offline_dir: Option<PathBuf>,\n    pub offline: Option<bool>,\n}\n\nimpl Metadata {\n    pub fn env(&self) -> crate::Result<Arc<MacrosEnv>> {\n        self.env\n            .get_or_try_init(|builder| load_env(&self.manifest_dir, &self.config, builder))\n    }\n\n    pub fn workspace_root(&self) -> PathBuf {\n        let mut root = self.workspace_root.lock().unwrap();\n        if root.is_none() {\n            use serde::Deserialize;\n            use std::process::Command;\n\n            let cargo = crate::env(\"CARGO\").unwrap();\n\n            let output = Command::new(cargo)\n                .args([\"metadata\", \"--format-version=1\", \"--no-deps\"])\n                .current_dir(&self.manifest_dir)\n                .env_remove(\"__CARGO_FIX_PLZ\")\n                .output()\n                .expect(\"Could not fetch metadata\");\n\n            #[derive(Deserialize)]\n            struct CargoMetadata {\n                workspace_root: PathBuf,\n            }\n\n            let metadata: CargoMetadata =\n                serde_json::from_slice(&output.stdout).expect(\"Invalid `cargo metadata` output\");\n\n            *root = Some(metadata.workspace_root);\n        }\n        root.clone().unwrap()\n    }\n}\n\npub fn try_for_crate() -> crate::Result<Arc<Metadata>> {\n    /// The `MtimeCache` in this type covers the config itself,\n    /// any changes to which will indirectly invalidate the loaded env vars as well.\n    #[expect(clippy::type_complexity)]\n    static METADATA: Mutex<\n        HashMap<String, Arc<MtimeCache<Arc<Metadata>>>, BuildHasherDefault<DefaultHasher>>,\n    > = Mutex::new(HashMap::with_hasher(BuildHasherDefault::new()));\n\n    let manifest_dir = crate::env(\"CARGO_MANIFEST_DIR\")?;\n\n    let cache = METADATA\n        .lock()\n        .expect(\"BUG: we shouldn't panic while holding this lock\")\n        .entry_ref(&manifest_dir)\n        .or_insert_with(|| Arc::new(MtimeCache::new()))\n        .clone();\n\n    cache.get_or_try_init(|builder| {\n        let manifest_dir = PathBuf::from(manifest_dir);\n        let config_path = manifest_dir.join(\"sqlx.toml\");\n\n        builder.add_path(config_path.clone());\n\n        let config = Config::try_from_path_or_default(config_path)?;\n\n        Ok(Arc::new(Metadata {\n            manifest_dir,\n            config,\n            env: MtimeCache::new(),\n            workspace_root: Default::default(),\n        }))\n    })\n}\n\nfn load_env(\n    manifest_dir: &Path,\n    config: &Config,\n    builder: &mut MtimeCacheBuilder,\n) -> crate::Result<Arc<MacrosEnv>> {\n    #[derive(thiserror::Error, Debug)]\n    #[error(\"error reading dotenv file {path:?}\")]\n    struct DotenvError {\n        path: PathBuf,\n        #[source]\n        error: dotenvy::Error,\n    }\n\n    let mut from_dotenv = MacrosEnv {\n        database_url: None,\n        offline_dir: None,\n        offline: None,\n    };\n\n    for dir in manifest_dir.ancestors() {\n        let path = dir.join(\".env\");\n\n        let dotenv = match dotenvy::from_path_iter(&path) {\n            Ok(iter) => {\n                builder.add_path(path.clone());\n                iter\n            }\n            Err(dotenvy::Error::Io(e)) if e.kind() == io::ErrorKind::NotFound => {\n                builder.add_path(dir.to_path_buf());\n                continue;\n            }\n            Err(e) => {\n                builder.add_path(path.clone());\n                return Err(DotenvError { path, error: e }.into());\n            }\n        };\n\n        for res in dotenv {\n            let (name, val) = res.map_err(|e| DotenvError {\n                path: path.clone(),\n                error: e,\n            })?;\n\n            match &*name {\n                \"SQLX_OFFLINE_DIR\" => from_dotenv.offline_dir = Some(val.into()),\n                \"SQLX_OFFLINE\" => from_dotenv.offline = Some(is_truthy_bool(&val)),\n                _ if name == config.common.database_url_var() => {\n                    from_dotenv.database_url = Some(val)\n                }\n                _ => continue,\n            }\n        }\n    }\n\n    Ok(Arc::new(MacrosEnv {\n        // Make set variables take precedent\n        database_url: crate::env_opt(config.common.database_url_var())?\n            .or(from_dotenv.database_url),\n        offline_dir: crate::env_opt(\"SQLX_OFFLINE_DIR\")?\n            .map(PathBuf::from)\n            .or(from_dotenv.offline_dir),\n        offline: crate::env_opt(\"SQLX_OFFLINE\")?\n            .map(|val| is_truthy_bool(&val))\n            .or(from_dotenv.offline),\n    }))\n}\n\n/// Returns `true` if `val` is `\"true\"`,\nfn is_truthy_bool(val: &str) -> bool {\n    val.eq_ignore_ascii_case(\"true\") || val == \"1\"\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/mod.rs",
    "content": "use std::path::{Path, PathBuf};\n\nuse proc_macro2::TokenStream;\nuse syn::Type;\n\npub use input::QueryMacroInput;\nuse quote::{format_ident, quote};\nuse sqlx_core::database::Database;\nuse sqlx_core::{column::Column, describe::Describe, type_info::TypeInfo};\n\nuse crate::database::DatabaseExt;\nuse crate::query::data::{hash_string, DynQueryData, QueryData};\nuse crate::query::input::RecordType;\nuse crate::query::metadata::MacrosEnv;\nuse either::Either;\nuse metadata::Metadata;\nuse sqlx_core::config::Config;\nuse url::Url;\n\nmod args;\nmod cache;\nmod data;\nmod input;\nmod metadata;\nmod output;\n\n#[derive(Copy, Clone)]\npub struct QueryDriver {\n    db_name: &'static str,\n    url_schemes: &'static [&'static str],\n    expand:\n        fn(&Config, QueryMacroInput, QueryDataSource, Option<&Path>) -> crate::Result<TokenStream>,\n}\n\nimpl QueryDriver {\n    pub const fn new<DB: DatabaseExt>() -> Self\n    where\n        Describe<DB>: serde::Serialize + serde::de::DeserializeOwned,\n    {\n        QueryDriver {\n            db_name: DB::NAME,\n            url_schemes: DB::URL_SCHEMES,\n            expand: expand_with::<DB>,\n        }\n    }\n}\npub enum QueryDataSource<'a> {\n    Live {\n        database_url: &'a str,\n        database_url_parsed: Url,\n    },\n    Cached(DynQueryData),\n}\n\nimpl<'a> QueryDataSource<'a> {\n    pub fn live(database_url: &'a str) -> crate::Result<Self> {\n        Ok(QueryDataSource::Live {\n            database_url,\n            database_url_parsed: database_url.parse()?,\n        })\n    }\n\n    pub fn matches_driver(&self, driver: &QueryDriver) -> bool {\n        match self {\n            Self::Live {\n                database_url_parsed,\n                ..\n            } => driver.url_schemes.contains(&database_url_parsed.scheme()),\n            Self::Cached(dyn_data) => dyn_data.db_name == driver.db_name,\n        }\n    }\n}\npub fn expand_input<'a>(\n    input: QueryMacroInput,\n    drivers: impl IntoIterator<Item = &'a QueryDriver>,\n) -> crate::Result<TokenStream> {\n    let metadata = metadata::try_for_crate()?;\n\n    let metadata_env = metadata.env()?;\n\n    let data_source = match &*metadata_env {\n        MacrosEnv {\n            offline: None | Some(false),\n            database_url: Some(db_url),\n            ..\n        }\n        // Allow `DATABASE_URL=''`\n        if !db_url.is_empty() => QueryDataSource::live(db_url)?,\n        MacrosEnv {\n            offline,\n            offline_dir,\n            ..\n        } => {\n            // Try load the cached query metadata file.\n            let filename = format!(\"query-{}.json\", hash_string(&input.sql));\n\n            // Check SQLX_OFFLINE_DIR, then local .sqlx, then workspace .sqlx.\n            let dirs = [\n                |_: &Metadata, offline_dir: Option<&Path>| offline_dir.map(PathBuf::from),\n                |meta: &Metadata, _: Option<&Path>| Some(meta.manifest_dir.join(\".sqlx\")),\n                |meta: &Metadata, _: Option<&Path>| Some(meta.workspace_root().join(\".sqlx\")),\n            ];\n\n            let Some(data_file_path) = dirs\n                .iter()\n                .filter_map(|path| path(&metadata, offline_dir.as_deref()))\n                .map(|path| path.join(&filename))\n                .find(|path| path.exists())\n            else {\n                return Err(\n                    if offline.unwrap_or(false) {\n                        \"`SQLX_OFFLINE=true` but there is no cached data for this query, run `cargo sqlx prepare` to update the query cache or unset `SQLX_OFFLINE`\"\n                    } else {\n                        \"set `DATABASE_URL` to use query macros online, or run `cargo sqlx prepare` to update the query cache\"\n                    }.into()\n                );\n            };\n\n            QueryDataSource::Cached(DynQueryData::from_data_file(&data_file_path, &input.sql)?)\n        }\n    };\n\n    for driver in drivers {\n        if data_source.matches_driver(driver) {\n            return (driver.expand)(\n                &metadata.config,\n                input,\n                data_source,\n                metadata_env.offline_dir.as_deref(),\n            );\n        }\n    }\n\n    match data_source {\n        QueryDataSource::Live {\n            database_url_parsed,\n            ..\n        } => Err(format!(\n            \"no database driver found matching URL scheme {:?}; the corresponding Cargo feature may need to be enabled\", \n            database_url_parsed.scheme()\n        ).into()),\n        QueryDataSource::Cached(data) => {\n            Err(format!(\n                \"found cached data for database {:?} but no matching driver; the corresponding Cargo feature may need to be enabled\",\n                data.db_name\n            ).into())\n        }\n    }\n}\n\nfn expand_with<DB: DatabaseExt>(\n    config: &Config,\n    input: QueryMacroInput,\n    data_source: QueryDataSource,\n    offline_dir: Option<&Path>,\n) -> crate::Result<TokenStream>\nwhere\n    Describe<DB>: DescribeExt,\n{\n    let (query_data, save_dir): (QueryData<DB>, Option<&Path>) = match data_source {\n        // If the build is offline, the cache is our input so it's pointless to also write data for it.\n        QueryDataSource::Cached(dyn_data) => (QueryData::from_dyn_data(dyn_data)?, None),\n        QueryDataSource::Live { database_url, .. } => {\n            let describe = DB::describe_blocking(&input.sql, database_url, &config.drivers)?;\n            (QueryData::from_describe(&input.sql, describe), offline_dir)\n        }\n    };\n\n    expand_with_data(config, input, query_data, save_dir)\n}\n\n// marker trait for `Describe` that lets us conditionally require it to be `Serialize + Deserialize`\ntrait DescribeExt: serde::Serialize + serde::de::DeserializeOwned {}\n\nimpl<DB: Database> DescribeExt for Describe<DB> where\n    Describe<DB>: serde::Serialize + serde::de::DeserializeOwned\n{\n}\n\n#[derive(Default)]\nstruct Warnings {\n    ambiguous_datetime: bool,\n    ambiguous_numeric: bool,\n}\n\nfn expand_with_data<DB: DatabaseExt>(\n    config: &Config,\n    input: QueryMacroInput,\n    data: QueryData<DB>,\n    save_dir: Option<&Path>,\n) -> crate::Result<TokenStream>\nwhere\n    Describe<DB>: DescribeExt,\n{\n    // validate at the minimum that our args match the query's input parameters\n    let num_parameters = match data.describe.parameters() {\n        Some(Either::Left(params)) => Some(params.len()),\n        Some(Either::Right(num)) => Some(num),\n\n        None => None,\n    };\n\n    if let Some(num) = num_parameters {\n        if num != input.arg_exprs.len() {\n            return Err(\n                format!(\"expected {} parameters, got {}\", num, input.arg_exprs.len()).into(),\n            );\n        }\n    }\n\n    let mut warnings = Warnings::default();\n\n    let args_tokens = args::quote_args(&input, config, &mut warnings, &data.describe)?;\n\n    let query_args = format_ident!(\"query_args\");\n\n    let output = if data\n        .describe\n        .columns()\n        .iter()\n        .all(|it| it.type_info().is_void())\n    {\n        let db_path = DB::db_path();\n        let sql = &input.sql;\n\n        quote! {\n            ::sqlx::__query_with_result::<#db_path, _>(#sql, #query_args)\n        }\n    } else {\n        match input.record_type {\n            RecordType::Generated => {\n                let columns = output::columns_to_rust::<DB>(&data.describe, config, &mut warnings)?;\n\n                let record_name: Type = syn::parse_str(\"Record\").unwrap();\n\n                for rust_col in &columns {\n                    if rust_col.type_.is_wildcard() {\n                        return Err(\n                            \"wildcard overrides are only allowed with an explicit record type, \\\n                             e.g. `query_as!()` and its variants\"\n                                .into(),\n                        );\n                    }\n                }\n\n                let record_fields = columns\n                    .iter()\n                    .map(|output::RustColumn { ident, type_, .. }| quote!(#ident: #type_,));\n\n                let mut record_tokens = quote! {\n                    #[derive(Debug)]\n                    #[allow(non_snake_case)]\n                    struct #record_name {\n                        #(#record_fields)*\n                    }\n                };\n\n                record_tokens.extend(output::quote_query_as::<DB>(\n                    &input,\n                    &record_name,\n                    &query_args,\n                    &columns,\n                ));\n\n                record_tokens\n            }\n            RecordType::Given(ref out_ty) => {\n                let columns = output::columns_to_rust::<DB>(&data.describe, config, &mut warnings)?;\n\n                output::quote_query_as::<DB>(&input, out_ty, &query_args, &columns)\n            }\n            RecordType::Scalar => output::quote_query_scalar::<DB>(\n                &input,\n                config,\n                &mut warnings,\n                &query_args,\n                &data.describe,\n            )?,\n        }\n    };\n\n    let mut warnings_out = TokenStream::new();\n\n    if warnings.ambiguous_datetime {\n        // Warns if the date-time crate is inferred but both `chrono` and `time` are enabled\n        warnings_out.extend(quote! {\n            ::sqlx::warn_on_ambiguous_inferred_date_time_crate();\n        });\n    }\n\n    if warnings.ambiguous_numeric {\n        // Warns if the numeric crate is inferred but both `bigdecimal` and `rust_decimal` are enabled\n        warnings_out.extend(quote! {\n            ::sqlx::warn_on_ambiguous_inferred_numeric_crate();\n        });\n    }\n\n    let ret_tokens = quote! {\n        {\n            #[allow(clippy::all)]\n            {\n                use ::sqlx::Arguments as _;\n\n                #warnings_out\n\n                #args_tokens\n\n                #output\n            }\n        }\n    };\n\n    if let Some(save_dir) = save_dir {\n        data.save_in(save_dir)?;\n    }\n\n    Ok(ret_tokens)\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/query/output.rs",
    "content": "use proc_macro2::{Ident, Span, TokenStream};\nuse quote::{quote, ToTokens, TokenStreamExt};\nuse syn::Type;\n\nuse sqlx_core::column::{Column, ColumnOrigin};\nuse sqlx_core::describe::Describe;\n\nuse crate::database::DatabaseExt;\n\nuse crate::query::{QueryMacroInput, Warnings};\nuse sqlx_core::config::Config;\nuse sqlx_core::type_checking;\nuse sqlx_core::type_checking::TypeChecking;\nuse sqlx_core::type_info::TypeInfo;\nuse std::fmt::{self, Display, Formatter};\nuse syn::parse::{Parse, ParseStream};\nuse syn::Token;\n\npub struct RustColumn {\n    pub(super) ident: Ident,\n    pub(super) var_name: Ident,\n    pub(super) type_: ColumnType,\n}\n\npub(super) enum ColumnType {\n    Exact(TokenStream),\n    Wildcard,\n    OptWildcard,\n}\n\nimpl ColumnType {\n    pub(super) fn is_wildcard(&self) -> bool {\n        !matches!(self, ColumnType::Exact(_))\n    }\n}\n\nimpl ToTokens for ColumnType {\n    fn to_tokens(&self, tokens: &mut TokenStream) {\n        tokens.append_all(match &self {\n            ColumnType::Exact(type_) => type_.clone().into_iter(),\n            ColumnType::Wildcard => quote! { _ }.into_iter(),\n            ColumnType::OptWildcard => quote! { ::std::option::Option<_> }.into_iter(),\n        })\n    }\n}\n\nstruct DisplayColumn<'a> {\n    // zero-based index, converted to 1-based number\n    idx: usize,\n    name: &'a str,\n}\n\nstruct ColumnDecl {\n    ident: Ident,\n    r#override: ColumnOverride,\n}\n\nstruct ColumnOverride {\n    nullability: ColumnNullabilityOverride,\n    type_: ColumnTypeOverride,\n}\n\n#[derive(PartialEq)]\nenum ColumnNullabilityOverride {\n    NonNull,\n    Nullable,\n    None,\n}\n\nenum ColumnTypeOverride {\n    Exact(Type),\n    Wildcard,\n    None,\n}\n\nimpl Display for DisplayColumn<'_> {\n    fn fmt(&self, f: &mut Formatter) -> fmt::Result {\n        write!(f, \"column #{} ({:?})\", self.idx + 1, self.name)\n    }\n}\n\npub fn columns_to_rust<DB: DatabaseExt>(\n    describe: &Describe<DB>,\n    config: &Config,\n    warnings: &mut Warnings,\n) -> crate::Result<Vec<RustColumn>> {\n    (0..describe.columns().len())\n        .map(|i| column_to_rust(describe, config, warnings, i))\n        .collect::<crate::Result<Vec<_>>>()\n}\n\nfn column_to_rust<DB: DatabaseExt>(\n    describe: &Describe<DB>,\n    config: &Config,\n    warnings: &mut Warnings,\n    i: usize,\n) -> crate::Result<RustColumn> {\n    let column = &describe.columns()[i];\n\n    // add raw prefix to all identifiers\n    let decl = ColumnDecl::parse(column.name())\n        .map_err(|e| format!(\"column name {:?} is invalid: {}\", column.name(), e))?;\n\n    let ColumnOverride { nullability, type_ } = decl.r#override;\n\n    let nullable = match nullability {\n        ColumnNullabilityOverride::NonNull => false,\n        ColumnNullabilityOverride::Nullable => true,\n        ColumnNullabilityOverride::None => describe.nullable(i).unwrap_or(true),\n    };\n    let type_ = match (type_, nullable) {\n        (ColumnTypeOverride::Exact(type_), false) => ColumnType::Exact(type_.to_token_stream()),\n        (ColumnTypeOverride::Exact(type_), true) => {\n            ColumnType::Exact(quote! { ::std::option::Option<#type_> })\n        }\n\n        (ColumnTypeOverride::Wildcard, false) => ColumnType::Wildcard,\n        (ColumnTypeOverride::Wildcard, true) => ColumnType::OptWildcard,\n\n        (ColumnTypeOverride::None, _) => {\n            let type_ = get_column_type::<DB>(config, warnings, i, column);\n            if !nullable {\n                ColumnType::Exact(type_)\n            } else {\n                ColumnType::Exact(quote! { ::std::option::Option<#type_> })\n            }\n        }\n    };\n\n    Ok(RustColumn {\n        // prefix the variable name we use in `quote_query_as!()` so it doesn't conflict\n        // https://github.com/launchbadge/sqlx/issues/1322\n        var_name: quote::format_ident!(\"sqlx_query_as_{}\", decl.ident),\n        ident: decl.ident,\n        type_,\n    })\n}\n\npub fn quote_query_as<DB: DatabaseExt>(\n    input: &QueryMacroInput,\n    out_ty: &Type,\n    bind_args: &Ident,\n    columns: &[RustColumn],\n) -> TokenStream {\n    let instantiations = columns.iter().enumerate().map(\n        |(\n            i,\n            RustColumn {\n                var_name, type_, ..\n            },\n        )| {\n            match (input.checked, type_) {\n                // we guarantee the type is valid so we can skip the runtime check\n                (true, ColumnType::Exact(type_)) => quote! {\n                    // binding to a `let` avoids confusing errors about\n                    // \"try expression alternatives have incompatible types\"\n                    // it doesn't seem to hurt inference in the other branches\n                    #[allow(non_snake_case)]\n                    let #var_name = row.try_get_unchecked::<#type_, _>(#i)?.into();\n                },\n                // type was overridden to be a wildcard so we fallback to the runtime check\n                (true, ColumnType::Wildcard) => quote! (\n                #[allow(non_snake_case)]\n                let #var_name = row.try_get(#i)?;\n                ),\n                (true, ColumnType::OptWildcard) => {\n                    quote! (\n                    #[allow(non_snake_case)]\n                    let #var_name = row.try_get::<::std::option::Option<_>, _>(#i)?;\n                    )\n                }\n                // macro is the `_unchecked!()` variant so this will die in decoding if it's wrong\n                (false, _) => quote!(\n                #[allow(non_snake_case)]\n                let #var_name = row.try_get_unchecked(#i)?;\n                ),\n            }\n        },\n    );\n\n    let ident = columns.iter().map(|col| &col.ident);\n    let var_name = columns.iter().map(|col| &col.var_name);\n\n    let db_path = DB::db_path();\n    let row_path = DB::row_path();\n\n    // if this query came from a file, use `include_str!()` to tell the compiler where it came from\n    let sql = if let Some(ref path) = &input.file_path {\n        quote::quote_spanned! { input.src_span => include_str!(#path) }\n    } else {\n        let sql = &input.sql;\n        quote! { #sql }\n    };\n\n    quote! {\n        ::sqlx::__query_with_result::<#db_path, _>(#sql, #bind_args).try_map(|row: #row_path| {\n            use ::sqlx::Row as _;\n\n            #(#instantiations)*\n\n            ::std::result::Result::Ok(#out_ty { #(#ident: #var_name),* })\n        })\n    }\n}\n\npub fn quote_query_scalar<DB: DatabaseExt>(\n    input: &QueryMacroInput,\n    config: &Config,\n    warnings: &mut Warnings,\n    bind_args: &Ident,\n    describe: &Describe<DB>,\n) -> crate::Result<TokenStream> {\n    let columns = describe.columns();\n\n    if columns.len() != 1 {\n        return Err(syn::Error::new(\n            input.src_span,\n            format!(\"expected exactly 1 column, got {}\", columns.len()),\n        )\n        .into());\n    }\n\n    // attempt to parse a column override, otherwise fall back to the inferred type of the column\n    let ty = if let Ok(rust_col) = column_to_rust(describe, config, warnings, 0) {\n        rust_col.type_.to_token_stream()\n    } else if input.checked {\n        let ty = get_column_type::<DB>(config, warnings, 0, &columns[0]);\n        if describe.nullable(0).unwrap_or(true) {\n            quote! { ::std::option::Option<#ty> }\n        } else {\n            ty\n        }\n    } else {\n        quote! { _ }\n    };\n\n    let db = DB::db_path();\n    let query = &input.sql;\n\n    Ok(quote! {\n        ::sqlx::__query_scalar_with_result::<#db, #ty, _>(#query, #bind_args)\n    })\n}\n\nfn get_column_type<DB: DatabaseExt>(\n    config: &Config,\n    warnings: &mut Warnings,\n    i: usize,\n    column: &DB::Column,\n) -> TokenStream {\n    if let ColumnOrigin::Table(origin) = column.origin() {\n        if let Some(column_override) = config.macros.column_override(&origin.table, &origin.name) {\n            return column_override.parse().unwrap();\n        }\n    }\n\n    let type_info = column.type_info();\n\n    if let Some(type_override) = config.macros.type_override(type_info.name()) {\n        return type_override.parse().unwrap();\n    }\n\n    let err = match <DB as TypeChecking>::return_type_for_id(\n        type_info,\n        &config.macros.preferred_crates,\n    ) {\n        Ok(t) => return t.parse().unwrap(),\n        Err(e) => e,\n    };\n\n    let message = match err {\n        type_checking::Error::NoMappingFound => {\n            if let Some(feature_gate) = <DB as TypeChecking>::get_feature_gate(type_info) {\n                format!(\n                    \"SQLx feature `{feat}` required for type {ty} of {col}\",\n                    ty = &type_info,\n                    feat = feature_gate,\n                    col = DisplayColumn {\n                        idx: i,\n                        name: column.name()\n                    }\n                )\n            } else {\n                format!(\n                    \"no built-in mapping found for type {ty} of {col}; \\\n                     a type override may be required, see documentation for details\",\n                    ty = type_info,\n                    col = DisplayColumn {\n                        idx: i,\n                        name: column.name()\n                    }\n                )\n            }\n        }\n        type_checking::Error::DateTimeCrateFeatureNotEnabled => {\n            let feature_gate = config\n                .macros\n                .preferred_crates\n                .date_time\n                .crate_name()\n                .expect(\"BUG: got feature-not-enabled error for DateTimeCrate::Inferred\");\n\n            format!(\n                \"SQLx feature `{feat}` required for type {ty} of {col} \\\n                 (configured by `macros.preferred-crates.date-time` in sqlx.toml)\",\n                ty = &type_info,\n                feat = feature_gate,\n                col = DisplayColumn {\n                    idx: i,\n                    name: column.name()\n                }\n            )\n        }\n        type_checking::Error::NumericCrateFeatureNotEnabled => {\n            let feature_gate = config\n                .macros\n                .preferred_crates\n                .numeric\n                .crate_name()\n                .expect(\"BUG: got feature-not-enabled error for NumericCrate::Inferred\");\n\n            format!(\n                \"SQLx feature `{feat}` required for type {ty} of {col} \\\n                 (configured by `macros.preferred-crates.numeric` in sqlx.toml)\",\n                ty = &type_info,\n                feat = feature_gate,\n                col = DisplayColumn {\n                    idx: i,\n                    name: column.name()\n                }\n            )\n        }\n        type_checking::Error::AmbiguousDateTimeType { fallback } => {\n            warnings.ambiguous_datetime = true;\n            return fallback.parse().unwrap();\n        }\n        type_checking::Error::AmbiguousNumericType { fallback } => {\n            warnings.ambiguous_numeric = true;\n            return fallback.parse().unwrap();\n        }\n    };\n\n    syn::Error::new(Span::call_site(), message).to_compile_error()\n}\n\nimpl ColumnDecl {\n    fn parse(col_name: &str) -> crate::Result<Self> {\n        // find the end of the identifier because we want to use our own logic to parse it\n        // if we tried to feed this into `syn::parse_str()` we might get an un-great error\n        // for some kinds of invalid identifiers\n        let (ident, remainder) = if let Some(i) = col_name.find(&[':', '!', '?'][..]) {\n            let (ident, remainder) = col_name.split_at(i);\n\n            (parse_ident(ident)?, remainder)\n        } else {\n            (parse_ident(col_name)?, \"\")\n        };\n\n        Ok(ColumnDecl {\n            ident,\n            r#override: if !remainder.is_empty() {\n                syn::parse_str(remainder)?\n            } else {\n                ColumnOverride {\n                    nullability: ColumnNullabilityOverride::None,\n                    type_: ColumnTypeOverride::None,\n                }\n            },\n        })\n    }\n}\n\nimpl Parse for ColumnOverride {\n    fn parse(input: ParseStream) -> syn::Result<Self> {\n        let lookahead = input.lookahead1();\n\n        let nullability = if lookahead.peek(Token![!]) {\n            input.parse::<Token![!]>()?;\n\n            ColumnNullabilityOverride::NonNull\n        } else if lookahead.peek(Token![?]) {\n            input.parse::<Token![?]>()?;\n\n            ColumnNullabilityOverride::Nullable\n        } else {\n            ColumnNullabilityOverride::None\n        };\n\n        let type_ = if input.lookahead1().peek(Token![:]) {\n            input.parse::<Token![:]>()?;\n\n            let ty = Type::parse(input)?;\n\n            if let Type::Infer(_) = ty {\n                ColumnTypeOverride::Wildcard\n            } else {\n                ColumnTypeOverride::Exact(ty)\n            }\n        } else {\n            ColumnTypeOverride::None\n        };\n\n        Ok(Self { nullability, type_ })\n    }\n}\n\nfn parse_ident(name: &str) -> crate::Result<Ident> {\n    // workaround for the following issue (it's semi-fixed but still spits out extra diagnostics)\n    // https://github.com/dtolnay/syn/issues/749#issuecomment-575451318\n\n    let is_valid_ident = !name.is_empty()\n        && name.starts_with(|c: char| c.is_alphabetic() || c == '_')\n        && name.chars().all(|c| c.is_alphanumeric() || c == '_');\n\n    if is_valid_ident {\n        let ident = String::from(\"r#\") + name;\n        if let Ok(ident) = syn::parse_str(&ident) {\n            return Ok(ident);\n        }\n    }\n\n    Err(format!(\"{name:?} is not a valid Rust identifier\").into())\n}\n"
  },
  {
    "path": "sqlx-macros-core/src/test_attr.rs",
    "content": "use proc_macro2::TokenStream;\nuse quote::quote;\nuse syn::parse::Parser;\n\n#[cfg(feature = \"migrate\")]\nstruct Args {\n    fixtures: Vec<(FixturesType, Vec<syn::LitStr>)>,\n    migrations: MigrationsOpt,\n}\n\n#[cfg(feature = \"migrate\")]\nenum FixturesType {\n    None,\n    RelativePath,\n    CustomRelativePath(syn::LitStr),\n    ExplicitPath,\n}\n\n#[cfg(feature = \"migrate\")]\nenum MigrationsOpt {\n    InferredPath,\n    ExplicitPath(syn::LitStr),\n    ExplicitMigrator(syn::Path),\n    Disabled,\n}\n\ntype AttributeArgs = syn::punctuated::Punctuated<syn::Meta, syn::Token![,]>;\n\npub fn expand(args: TokenStream, input: syn::ItemFn) -> crate::Result<TokenStream> {\n    let parser = AttributeArgs::parse_terminated;\n    let args = parser.parse2(args)?;\n\n    if input.sig.inputs.is_empty() {\n        if !args.is_empty() {\n            if cfg!(not(feature = \"migrate\")) {\n                return Err(syn::Error::new_spanned(\n                    args.first().unwrap(),\n                    \"control attributes are not allowed unless \\\n                        the `migrate` feature is enabled and \\\n                        automatic test DB management is used; see docs\",\n                )\n                .into());\n            }\n\n            return Err(syn::Error::new_spanned(\n                args.first().unwrap(),\n                \"control attributes are not allowed unless \\\n                    automatic test DB management is used; see docs\",\n            )\n            .into());\n        }\n\n        return Ok(expand_simple(input));\n    }\n\n    #[cfg(feature = \"migrate\")]\n    return expand_advanced(args, input);\n\n    #[cfg(not(feature = \"migrate\"))]\n    return Err(syn::Error::new_spanned(input, \"`migrate` feature required\").into());\n}\n\nfn expand_simple(input: syn::ItemFn) -> TokenStream {\n    let ret = &input.sig.output;\n    let name = &input.sig.ident;\n    let body = &input.block;\n    let attrs = &input.attrs;\n\n    quote! {\n        #[::core::prelude::v1::test]\n        #(#attrs)*\n        fn #name() #ret {\n            ::sqlx::test_block_on(async { #body })\n        }\n    }\n}\n\n#[cfg(feature = \"migrate\")]\nfn expand_advanced(args: AttributeArgs, input: syn::ItemFn) -> crate::Result<TokenStream> {\n    let config = sqlx_core::config::Config::try_from_crate_or_default()?;\n\n    let ret = &input.sig.output;\n    let name = &input.sig.ident;\n    let inputs = &input.sig.inputs;\n    let body = &input.block;\n    let attrs = &input.attrs;\n\n    let args = parse_args(args)?;\n\n    let fn_arg_types = inputs.iter().map(|_| quote! { _ });\n\n    let mut fixtures = Vec::new();\n\n    for (fixture_type, fixtures_local) in args.fixtures {\n        let mut res = match fixture_type {\n            FixturesType::None => vec![],\n            FixturesType::RelativePath => fixtures_local\n                .into_iter()\n                .map(|fixture| {\n                    let mut fixture_str = fixture.value();\n                    add_sql_extension_if_missing(&mut fixture_str);\n\n                    let path = format!(\"fixtures/{}\", fixture_str);\n\n                    quote! {\n                        ::sqlx::testing::TestFixture {\n                            path: #path,\n                            contents: include_str!(#path),\n                        }\n                    }\n                })\n                .collect(),\n            FixturesType::CustomRelativePath(path) => fixtures_local\n                .into_iter()\n                .map(|fixture| {\n                    let mut fixture_str = fixture.value();\n                    add_sql_extension_if_missing(&mut fixture_str);\n\n                    let path = format!(\"{}/{}\", path.value(), fixture_str);\n\n                    quote! {\n                        ::sqlx::testing::TestFixture {\n                            path: #path,\n                            contents: include_str!(#path),\n                        }\n                    }\n                })\n                .collect(),\n            FixturesType::ExplicitPath => fixtures_local\n                .into_iter()\n                .map(|fixture| {\n                    let path = fixture.value();\n\n                    quote! {\n                        ::sqlx::testing::TestFixture {\n                            path: #path,\n                            contents: include_str!(#path),\n                        }\n                    }\n                })\n                .collect(),\n        };\n        fixtures.append(&mut res)\n    }\n\n    let migrations = match args.migrations {\n        MigrationsOpt::ExplicitPath(path) => {\n            let migrator = crate::migrate::expand(Some(path))?;\n            quote! { args.migrator(&#migrator); }\n        }\n        MigrationsOpt::InferredPath if !inputs.is_empty() => {\n            let path = crate::migrate::default_path(&config);\n\n            let resolved_path = crate::common::resolve_path(path, proc_macro2::Span::call_site())?;\n\n            if resolved_path.is_dir() {\n                let migrator = crate::migrate::expand_with_path(&config, &resolved_path)?;\n                quote! { args.migrator(&#migrator); }\n            } else {\n                quote! {}\n            }\n        }\n        MigrationsOpt::ExplicitMigrator(path) => {\n            quote! { args.migrator(&#path); }\n        }\n        _ => quote! {},\n    };\n\n    Ok(quote! {\n        #(#attrs)*\n        #[::core::prelude::v1::test]\n        fn #name() #ret {\n            async fn #name(#inputs) #ret {\n                #body\n            }\n\n            let mut args = ::sqlx::testing::TestArgs::new(concat!(module_path!(), \"::\", stringify!(#name)));\n\n            #migrations\n\n            args.fixtures(&[#(#fixtures),*]);\n\n            // We need to give a coercion site or else we get \"unimplemented trait\" errors.\n            let f: fn(#(#fn_arg_types),*) -> _ = #name;\n\n            ::sqlx::testing::TestFn::run_test(f, args)\n        }\n    })\n}\n\n#[cfg(feature = \"migrate\")]\nfn parse_args(attr_args: AttributeArgs) -> syn::Result<Args> {\n    use syn::{\n        parenthesized, parse::Parse, punctuated::Punctuated, token::Comma, Expr, Lit, LitStr, Meta,\n        MetaNameValue, Token,\n    };\n\n    let mut fixtures = Vec::new();\n    let mut migrations = MigrationsOpt::InferredPath;\n\n    for arg in attr_args {\n        let path = arg.path().clone();\n\n        match arg {\n            syn::Meta::List(list) if list.path.is_ident(\"fixtures\") => {\n                let mut fixtures_local = vec![];\n                let mut fixtures_type = FixturesType::None;\n\n                let parse_nested = list.parse_nested_meta(|meta| {\n                    if meta.path.is_ident(\"path\") {\n                        //  fixtures(path = \"<path>\", scripts(\"<file_1>\",\"<file_2>\")) checking `path` argument\n                        meta.input.parse::<Token![=]>()?;\n                        let val: LitStr = meta.input.parse()?;\n                        parse_fixtures_path_args(&mut fixtures_type, val)?;\n                    } else if meta.path.is_ident(\"scripts\") {\n                        //  fixtures(path = \"<path>\", scripts(\"<file_1>\",\"<file_2>\")) checking `scripts` argument\n                        let content;\n                        parenthesized!(content in meta.input);\n                        let list = content.parse_terminated(<LitStr as Parse>::parse, Comma)?;\n                        parse_fixtures_scripts_args(&mut fixtures_type, list, &mut fixtures_local)?;\n                    } else {\n                        return Err(syn::Error::new_spanned(\n                            meta.path,\n                            \"unexpected fixture meta\",\n                        ));\n                    }\n\n                    Ok(())\n                });\n\n                if parse_nested.is_err() {\n                    // fixtures(\"<file_1>\",\"<file_2>\") or fixtures(\"<path/file_1.sql>\",\"<path/file_2.sql>\")\n                    let args =\n                        list.parse_args_with(<Punctuated<LitStr, Token![,]>>::parse_terminated)?;\n                    for arg in args {\n                        parse_fixtures_args(&mut fixtures_type, arg, &mut fixtures_local)?;\n                    }\n                }\n\n                fixtures.push((fixtures_type, fixtures_local));\n            }\n            syn::Meta::NameValue(value) if value.path.is_ident(\"migrations\") => {\n                if !matches!(migrations, MigrationsOpt::InferredPath) {\n                    return Err(syn::Error::new_spanned(\n                        value,\n                        \"cannot have more than one `migrations` or `migrator` arg\",\n                    ));\n                }\n\n                fn recurse_lit_lookup(expr: Expr) -> Option<Lit> {\n                    match expr {\n                        Expr::Lit(syn::ExprLit { lit, .. }) => Some(lit),\n                        Expr::Group(syn::ExprGroup { expr, .. }) => recurse_lit_lookup(*expr),\n                        _ => None,\n                    }\n                }\n\n                let Some(lit) = recurse_lit_lookup(value.value) else {\n                    return Err(syn::Error::new_spanned(path, \"expected string or `false`\"));\n                };\n\n                migrations = match lit {\n                    // migrations = false\n                    Lit::Bool(b) if !b.value => MigrationsOpt::Disabled,\n                    // migrations = true\n                    Lit::Bool(b) => {\n                        return Err(syn::Error::new_spanned(\n                            b,\n                            \"`migrations = true` is redundant\",\n                        ));\n                    }\n                    // migrations = \"path\"\n                    Lit::Str(s) => MigrationsOpt::ExplicitPath(s),\n                    lit => return Err(syn::Error::new_spanned(lit, \"expected string or `false`\")),\n                };\n            }\n            // migrator = \"<path>\"\n            Meta::NameValue(MetaNameValue { value, .. }) if path.is_ident(\"migrator\") => {\n                if !matches!(migrations, MigrationsOpt::InferredPath) {\n                    return Err(syn::Error::new_spanned(\n                        path,\n                        \"cannot have more than one `migrations` or `migrator` arg\",\n                    ));\n                }\n\n                let Expr::Lit(syn::ExprLit {\n                    lit: Lit::Str(lit), ..\n                }) = value\n                else {\n                    return Err(syn::Error::new_spanned(path, \"expected string\"));\n                };\n\n                migrations = MigrationsOpt::ExplicitMigrator(lit.parse()?);\n            }\n            arg => {\n                return Err(syn::Error::new_spanned(\n                    arg,\n                    r#\"expected `fixtures(\"<filename>\", ...)` or `migrations = \"<path>\" | false` or `migrator = \"<rust path>\"`\"#,\n                ))\n            }\n        }\n    }\n\n    Ok(Args {\n        fixtures,\n        migrations,\n    })\n}\n\n#[cfg(feature = \"migrate\")]\nfn parse_fixtures_args(\n    fixtures_type: &mut FixturesType,\n    litstr: syn::LitStr,\n    fixtures_local: &mut Vec<syn::LitStr>,\n) -> syn::Result<()> {\n    //  fixtures(path = \"<path>\", scripts(\"<file_1>\",\"<file_2>\")) checking `path` argument\n    let path_str = litstr.value();\n    let path = std::path::Path::new(&path_str);\n    // This will be `true` if there's at least one path separator (`/` or `\\`)\n    // It's also true for all absolute paths, even e.g. `/foo.sql` as the root directory is counted as a component.\n    let is_explicit_path = path.components().count() > 1;\n    match fixtures_type {\n        FixturesType::None => {\n            if is_explicit_path {\n                *fixtures_type = FixturesType::ExplicitPath;\n            } else {\n                *fixtures_type = FixturesType::RelativePath;\n            }\n        }\n        FixturesType::RelativePath => {\n            if is_explicit_path {\n                return Err(syn::Error::new_spanned(\n                    litstr,\n                    \"expected only relative path fixtures\",\n                ));\n            }\n        }\n        FixturesType::ExplicitPath => {\n            if !is_explicit_path {\n                return Err(syn::Error::new_spanned(\n                    litstr,\n                    \"expected only explicit path fixtures\",\n                ));\n            }\n        }\n        FixturesType::CustomRelativePath(_) => {\n            return Err(syn::Error::new_spanned(\n                litstr,\n                \"custom relative path fixtures must be defined in `scripts` argument\",\n            ))\n        }\n    }\n    if (matches!(fixtures_type, FixturesType::ExplicitPath) && !is_explicit_path) {\n        return Err(syn::Error::new_spanned(\n            litstr,\n            \"expected explicit path fixtures to have `.sql` extension\",\n        ));\n    }\n    fixtures_local.push(litstr);\n    Ok(())\n}\n\n#[cfg(feature = \"migrate\")]\nfn parse_fixtures_path_args(\n    fixtures_type: &mut FixturesType,\n    namevalue: syn::LitStr,\n) -> syn::Result<()> {\n    if !matches!(fixtures_type, FixturesType::None) {\n        return Err(syn::Error::new_spanned(\n            namevalue,\n            \"`path` must be the first argument of `fixtures`\",\n        ));\n    }\n    *fixtures_type = FixturesType::CustomRelativePath(namevalue);\n    Ok(())\n}\n\n#[cfg(feature = \"migrate\")]\nfn parse_fixtures_scripts_args(\n    fixtures_type: &mut FixturesType,\n    list: syn::punctuated::Punctuated<syn::LitStr, syn::Token![,]>,\n    fixtures_local: &mut Vec<syn::LitStr>,\n) -> syn::Result<()> {\n    //  fixtures(path = \"<path>\", scripts(\"<file_1>\",\"<file_2>\")) checking `scripts` argument\n\n    if !matches!(fixtures_type, FixturesType::CustomRelativePath(_)) {\n        return Err(syn::Error::new_spanned(\n            list,\n            \"`scripts` must be the second argument of `fixtures` and used together with `path`\",\n        ));\n    }\n\n    fixtures_local.extend(list);\n    Ok(())\n}\n\n#[cfg(feature = \"migrate\")]\nfn add_sql_extension_if_missing(fixture: &mut String) {\n    let has_extension = std::path::Path::new(&fixture).extension().is_some();\n    if !has_extension {\n        fixture.push_str(\".sql\")\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/Cargo.toml",
    "content": "[package]\nname = \"sqlx-mysql\"\ndocumentation = \"https://docs.rs/sqlx\"\ndescription = \"MySQL driver implementation for SQLx. Not for direct use; see the `sqlx` crate for details.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n[features]\njson = [\"sqlx-core/json\", \"serde\"]\nany = [\"sqlx-core/any\"]\noffline = [\"sqlx-core/offline\", \"serde/derive\", \"bitflags/serde\"]\nmigrate = [\"sqlx-core/migrate\"]\n\n# Type Integration features\nbigdecimal = [\"dep:bigdecimal\", \"sqlx-core/bigdecimal\"]\nchrono = [\"dep:chrono\", \"sqlx-core/chrono\"]\nrust_decimal = [\"dep:rust_decimal\", \"rust_decimal/maths\", \"sqlx-core/rust_decimal\"]\ntime = [\"dep:time\", \"sqlx-core/time\"]\nuuid = [\"dep:uuid\", \"sqlx-core/uuid\"]\n\n[dependencies]\nsqlx-core = { workspace = true }\n\n# Futures crates\nfutures-channel = { version = \"0.3.19\", default-features = false, features = [\"sink\", \"alloc\", \"std\"] }\nfutures-core = { version = \"0.3.19\", default-features = false }\nfutures-io = \"0.3.24\"\nfutures-util = { version = \"0.3.19\", default-features = false, features = [\"alloc\", \"sink\", \"io\"] }\n\n# Cryptographic Primitives\ncrc = \"3.0.0\"\ndigest = { version = \"0.10.0\", default-features = false, features = [\"std\"] }\nhkdf = \"0.12.0\"\nhmac = { version = \"0.12.0\", default-features = false }\nmd-5 = { version = \"0.10.0\", default-features = false }\nrand = { version = \"0.8.4\", default-features = false, features = [\"std\", \"std_rng\"] }\nrsa = \"0.9\"\nsha1 = { version = \"0.10.1\", default-features = false }\nsha2 = { version = \"0.10.0\", default-features = false }\n\n# Type Integrations (versions inherited from `[workspace.dependencies]`)\nbigdecimal = { workspace = true, optional = true }\nchrono = { workspace = true, optional = true }\nrust_decimal = { workspace = true, optional = true }\ntime = { workspace = true, optional = true }\nuuid = { workspace = true, optional = true }\n\n# Misc\natoi = \"2.0\"\nbase64 = { version = \"0.22.0\", default-features = false, features = [\"std\"] }\nbitflags = { version = \"2\", default-features = false }\nbyteorder = { version = \"1.4.3\", default-features = false, features = [\"std\"] }\nbytes = \"1.1.0\"\neither = \"1.6.1\"\ngeneric-array = { version = \"0.14.4\", default-features = false }\nhex = \"0.4.3\"\nitoa = \"1.0.1\"\nlog = \"0.4.18\"\nmemchr = { version = \"2.4.1\", default-features = false }\npercent-encoding = \"2.1.0\"\nsmallvec = \"1.7.0\"\nstringprep = \"0.1.2\"\ntracing = { version = \"0.1.37\", features = [\"log\"] }\n\ndotenvy.workspace = true\nthiserror.workspace = true\n\nserde = { version = \"1.0.144\", optional = true }\n\n[dev-dependencies]\n# FIXME: https://github.com/rust-lang/cargo/issues/15622\nsqlx = { path = \"..\", default-features = false, features = [\"mysql\"] }\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "sqlx-mysql/src/any.rs",
    "content": "use crate::protocol::text::ColumnType;\nuse crate::{\n    MySql, MySqlColumn, MySqlConnectOptions, MySqlConnection, MySqlQueryResult, MySqlRow,\n    MySqlTransactionManager, MySqlTypeInfo,\n};\nuse either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::{stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt};\nuse sqlx_core::any::{\n    AnyArguments, AnyColumn, AnyConnectOptions, AnyConnectionBackend, AnyQueryResult, AnyRow,\n    AnyStatement, AnyTypeInfo, AnyTypeInfoKind,\n};\nuse sqlx_core::connection::Connection;\nuse sqlx_core::database::Database;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::sql_str::SqlStr;\nuse sqlx_core::transaction::TransactionManager;\nuse std::{future, pin::pin};\n\nsqlx_core::declare_driver_with_optional_migrate!(DRIVER = MySql);\n\nimpl AnyConnectionBackend for MySqlConnection {\n    fn name(&self) -> &str {\n        <MySql as Database>::NAME\n    }\n\n    fn close(self: Box<Self>) -> BoxFuture<'static, sqlx_core::Result<()>> {\n        Connection::close(*self).boxed()\n    }\n\n    fn close_hard(self: Box<Self>) -> BoxFuture<'static, sqlx_core::Result<()>> {\n        Connection::close_hard(*self).boxed()\n    }\n\n    fn ping(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        Connection::ping(self).boxed()\n    }\n\n    fn begin(&mut self, statement: Option<SqlStr>) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        MySqlTransactionManager::begin(self, statement).boxed()\n    }\n\n    fn commit(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        MySqlTransactionManager::commit(self).boxed()\n    }\n\n    fn rollback(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        MySqlTransactionManager::rollback(self).boxed()\n    }\n\n    fn start_rollback(&mut self) {\n        MySqlTransactionManager::start_rollback(self)\n    }\n\n    fn get_transaction_depth(&self) -> usize {\n        MySqlTransactionManager::get_transaction_depth(self)\n    }\n\n    fn shrink_buffers(&mut self) {\n        Connection::shrink_buffers(self);\n    }\n\n    fn flush(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        Connection::flush(self).boxed()\n    }\n\n    fn should_flush(&self) -> bool {\n        Connection::should_flush(self)\n    }\n\n    #[cfg(feature = \"migrate\")]\n    fn as_migrate(\n        &mut self,\n    ) -> sqlx_core::Result<&mut (dyn sqlx_core::migrate::Migrate + Send + 'static)> {\n        Ok(self)\n    }\n\n    fn fetch_many(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxStream<'_, sqlx_core::Result<Either<AnyQueryResult, AnyRow>>> {\n        let persistent = persistent && arguments.is_some();\n        let arguments = match arguments.map(AnyArguments::convert_into).transpose() {\n            Ok(arguments) => arguments,\n            Err(error) => {\n                return stream::once(future::ready(Err(sqlx_core::Error::Encode(error)))).boxed()\n            }\n        };\n\n        Box::pin(\n            self.run(query, arguments, persistent)\n                .try_flatten_stream()\n                .map(|res| {\n                    Ok(match res? {\n                        Either::Left(result) => Either::Left(map_result(result)),\n                        Either::Right(row) => Either::Right(AnyRow::try_from(&row)?),\n                    })\n                }),\n        )\n    }\n\n    fn fetch_optional(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxFuture<'_, sqlx_core::Result<Option<AnyRow>>> {\n        let persistent = persistent && arguments.is_some();\n        let arguments = arguments\n            .map(AnyArguments::convert_into)\n            .transpose()\n            .map_err(sqlx_core::Error::Encode);\n\n        Box::pin(async move {\n            let arguments = arguments?;\n            let mut stream = pin!(self.run(query, arguments, persistent).await?);\n\n            while let Some(result) = stream.try_next().await? {\n                if let Either::Right(row) = result {\n                    return Ok(Some(AnyRow::try_from(&row)?));\n                }\n            }\n\n            Ok(None)\n        })\n    }\n\n    fn prepare_with<'c, 'q: 'c>(\n        &'c mut self,\n        sql: SqlStr,\n        _parameters: &[AnyTypeInfo],\n    ) -> BoxFuture<'c, sqlx_core::Result<AnyStatement>> {\n        Box::pin(async move {\n            let statement = Executor::prepare_with(self, sql, &[]).await?;\n            let column_names = statement.metadata.column_names.clone();\n            AnyStatement::try_from_statement(statement, column_names)\n        })\n    }\n\n    #[cfg(feature = \"offline\")]\n    fn describe(\n        &mut self,\n        sql: SqlStr,\n    ) -> BoxFuture<'_, sqlx_core::Result<sqlx_core::describe::Describe<sqlx_core::any::Any>>> {\n        Box::pin(async move {\n            let describe = Executor::describe(self, sql).await?;\n            describe.try_into_any()\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a MySqlTypeInfo> for AnyTypeInfo {\n    type Error = sqlx_core::Error;\n\n    fn try_from(type_info: &'a MySqlTypeInfo) -> Result<Self, Self::Error> {\n        Ok(AnyTypeInfo {\n            kind: match &type_info.r#type {\n                ColumnType::Null => AnyTypeInfoKind::Null,\n                ColumnType::Short => AnyTypeInfoKind::SmallInt,\n                ColumnType::Long => AnyTypeInfoKind::Integer,\n                ColumnType::LongLong => AnyTypeInfoKind::BigInt,\n                ColumnType::Float => AnyTypeInfoKind::Real,\n                ColumnType::Double => AnyTypeInfoKind::Double,\n                ColumnType::Blob\n                | ColumnType::TinyBlob\n                | ColumnType::MediumBlob\n                | ColumnType::LongBlob => AnyTypeInfoKind::Blob,\n                ColumnType::String | ColumnType::VarString | ColumnType::VarChar => {\n                    AnyTypeInfoKind::Text\n                }\n                _ => {\n                    return Err(sqlx_core::Error::AnyDriverError(\n                        format!(\"Any driver does not support MySql type {type_info:?}\").into(),\n                    ))\n                }\n            },\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a MySqlColumn> for AnyColumn {\n    type Error = sqlx_core::Error;\n\n    fn try_from(column: &'a MySqlColumn) -> Result<Self, Self::Error> {\n        let type_info = AnyTypeInfo::try_from(&column.type_info)?;\n\n        Ok(AnyColumn {\n            ordinal: column.ordinal,\n            name: column.name.clone(),\n            type_info,\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a MySqlRow> for AnyRow {\n    type Error = sqlx_core::Error;\n\n    fn try_from(row: &'a MySqlRow) -> Result<Self, Self::Error> {\n        AnyRow::map_from(row, row.column_names.clone())\n    }\n}\n\nimpl<'a> TryFrom<&'a AnyConnectOptions> for MySqlConnectOptions {\n    type Error = sqlx_core::Error;\n\n    fn try_from(any_opts: &'a AnyConnectOptions) -> Result<Self, Self::Error> {\n        let mut opts = Self::parse_from_url(&any_opts.database_url)?;\n        opts.log_settings = any_opts.log_settings.clone();\n        Ok(opts)\n    }\n}\n\nfn map_result(result: MySqlQueryResult) -> AnyQueryResult {\n    AnyQueryResult {\n        rows_affected: result.rows_affected,\n        // Don't expect this to be a problem\n        #[allow(clippy::cast_possible_wrap)]\n        last_insert_id: Some(result.last_insert_id as i64),\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/arguments.rs",
    "content": "use crate::encode::{Encode, IsNull};\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo};\npub(crate) use sqlx_core::arguments::*;\nuse sqlx_core::error::BoxDynError;\nuse std::ops::Deref;\n\n/// Implementation of [`Arguments`] for MySQL.\n#[derive(Debug, Default, Clone)]\npub struct MySqlArguments {\n    pub(crate) values: Vec<u8>,\n    pub(crate) types: Vec<MySqlTypeInfo>,\n    pub(crate) null_bitmap: NullBitMap,\n}\n\nimpl MySqlArguments {\n    pub(crate) fn add<'q, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'q, MySql> + Type<MySql>,\n    {\n        let ty = value.produces().unwrap_or_else(T::type_info);\n\n        let value_length_before_encoding = self.values.len();\n        let is_null = match value.encode(&mut self.values) {\n            Ok(is_null) => is_null,\n            Err(error) => {\n                // reset the value buffer to its previous value if encoding failed so we don't leave a half-encoded value behind\n                self.values.truncate(value_length_before_encoding);\n                return Err(error);\n            }\n        };\n\n        self.types.push(ty);\n        self.null_bitmap.push(is_null);\n\n        Ok(())\n    }\n}\n\nimpl Arguments for MySqlArguments {\n    type Database = MySql;\n\n    fn reserve(&mut self, len: usize, size: usize) {\n        self.types.reserve(len);\n        self.values.reserve(size);\n    }\n\n    fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'t, Self::Database> + Type<Self::Database>,\n    {\n        self.add(value)\n    }\n\n    fn len(&self) -> usize {\n        self.types.len()\n    }\n}\n\n#[derive(Debug, Default, Clone)]\npub(crate) struct NullBitMap {\n    bytes: Vec<u8>,\n    length: usize,\n}\n\nimpl NullBitMap {\n    fn push(&mut self, is_null: IsNull) {\n        let byte_index = self.length / (u8::BITS as usize);\n        let bit_offset = self.length % (u8::BITS as usize);\n\n        if bit_offset == 0 {\n            self.bytes.push(0);\n        }\n\n        self.bytes[byte_index] |= u8::from(is_null.is_null()) << bit_offset;\n        self.length += 1;\n    }\n}\n\nimpl Deref for NullBitMap {\n    type Target = [u8];\n\n    fn deref(&self) -> &Self::Target {\n        &self.bytes\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n\n    #[test]\n    fn null_bit_map_should_push_is_null() {\n        let mut bit_map = NullBitMap::default();\n\n        bit_map.push(IsNull::Yes);\n        bit_map.push(IsNull::No);\n        bit_map.push(IsNull::Yes);\n        bit_map.push(IsNull::No);\n        bit_map.push(IsNull::Yes);\n        bit_map.push(IsNull::No);\n        bit_map.push(IsNull::Yes);\n        bit_map.push(IsNull::No);\n        bit_map.push(IsNull::Yes);\n\n        assert_eq!([0b01010101, 0b1].as_slice(), bit_map.deref());\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/collation.rs",
    "content": "// One of several questionable design decisions in MySQL is the choice to conflate\n// *how stored data is sorted* with the character encoding used over the wire.\n//\n// The documentation for `Protocol::HandshakeResponse41` implies that\n// the lower 8 bits of the collation ID may be used to uniquely identify the character set:\n// https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_packets_protocol_handshake_response.html\n//\n// However, this isn't at _all_ true in practice. Collation IDs are assigned without any apparent\n// rhyme or reason, mostly just sequential with unexplained gaps. Masking the collation ID with 0xFF\n// doesn't actually tell you anything meaningful, except obviously for collation IDs under 256\n// which just gives you the same collation ID again.\n//\n// Hanlon's razor would suggest they just forgot that they told clients they could do this.\n// Occam's razor suggests no one ever bothers to set the connection charset/collation this way,\n// and they all just default to `latin1_swedish_ci` (8), `utf8mb4_general_ci` (45),\n// or `utf8mb4_0900_ai_ci` (255).\n//\n// This would seem to mean that if we want to be *sure* of the character encoding of a given column,\n// we have to reference the _full_ catalog of collations. Because new ones are added occasionally,\n// we can't just assume a collation we don't recognize is UTF-8 as that's not always the case.\n//\n// This is especially true when we include MariaDB because they've started creating\n// their *own* collations, and even character sets, separately from MySQL.\n//\n// Awesome, right?\n//\n// However, as long as `character_set_client` and `character_set_results` are set correctly,\n// we can assume that any non-binary collation is a valid string, because the server will transcode.\n// As it turns out, the collation specified in the `Protocol::ColumnDefinition`\n// is *purely* informational. It has no bearing on what's sent over the wire except for `binary` (63),\n// which is never transcoded.\n//\n// So at the end of the day, none of this matters anyway! To know if a column is a string or not,\n// we merely need to check if it's not `binary` (63). If the protocol was just a *bit*\n// better documented, it would have saved me literally six hours spent figuring this out.\n//\n// Thanks, MySQL.\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\n#[cfg_attr(feature = \"offline\", derive(serde::Deserialize, serde::Serialize))]\npub struct Collation(pub u16);\n\nimpl Collation {\n    /// Collation used for all non-string data.\n    pub const BINARY: Self = Collation(63);\n\n    /// Most broadly supported UTF-8 collation.\n    pub const UTF8MB4_GENERAL_CI: Self = Collation(45);\n}\n"
  },
  {
    "path": "sqlx-mysql/src/column.rs",
    "content": "use crate::ext::ustr::UStr;\nuse crate::protocol::text::ColumnFlags;\nuse crate::{MySql, MySqlTypeInfo};\npub(crate) use sqlx_core::column::*;\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct MySqlColumn {\n    pub(crate) ordinal: usize,\n    pub(crate) name: UStr,\n    pub(crate) type_info: MySqlTypeInfo,\n\n    #[cfg_attr(feature = \"offline\", serde(default))]\n    pub(crate) origin: ColumnOrigin,\n\n    #[allow(unused)]\n    #[cfg_attr(feature = \"offline\", serde(skip))]\n    pub(crate) flags: Option<ColumnFlags>,\n}\n\nimpl Column for MySqlColumn {\n    type Database = MySql;\n\n    fn ordinal(&self) -> usize {\n        self.ordinal\n    }\n\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn type_info(&self) -> &MySqlTypeInfo {\n        &self.type_info\n    }\n\n    fn origin(&self) -> ColumnOrigin {\n        self.origin.clone()\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/connection/auth.rs",
    "content": "use bytes::buf::Chain;\nuse bytes::Bytes;\nuse digest::{Digest, OutputSizeUser};\nuse generic_array::GenericArray;\nuse rand::thread_rng;\nuse rsa::{pkcs8::DecodePublicKey, Oaep, RsaPublicKey};\nuse sha1::Sha1;\nuse sha2::Sha256;\n\nuse crate::connection::stream::MySqlStream;\nuse crate::error::Error;\nuse crate::protocol::auth::AuthPlugin;\nuse crate::protocol::Packet;\n\nimpl AuthPlugin {\n    pub(super) async fn scramble(\n        self,\n        stream: &mut MySqlStream,\n        password: &str,\n        nonce: &Chain<Bytes, Bytes>,\n    ) -> Result<Vec<u8>, Error> {\n        match self {\n            // https://mariadb.com/kb/en/caching_sha2_password-authentication-plugin/\n            AuthPlugin::CachingSha2Password => Ok(scramble_sha256(password, nonce).to_vec()),\n\n            AuthPlugin::MySqlNativePassword => Ok(scramble_sha1(password, nonce).to_vec()),\n\n            // https://mariadb.com/kb/en/sha256_password-plugin/\n            AuthPlugin::Sha256Password => encrypt_rsa(stream, 0x01, password, nonce).await,\n\n            AuthPlugin::MySqlClearPassword => {\n                let mut pw_bytes = password.as_bytes().to_owned();\n                pw_bytes.push(0); // null terminate\n                Ok(pw_bytes)\n            }\n        }\n    }\n\n    pub(super) async fn handle(\n        self,\n        stream: &mut MySqlStream,\n        packet: Packet<Bytes>,\n        password: &str,\n        nonce: &Chain<Bytes, Bytes>,\n    ) -> Result<bool, Error> {\n        match self {\n            AuthPlugin::CachingSha2Password if packet[0] == 0x01 => {\n                match packet[1] {\n                    // AUTH_OK\n                    0x03 => Ok(true),\n\n                    // AUTH_CONTINUE\n                    0x04 => {\n                        let payload = encrypt_rsa(stream, 0x02, password, nonce).await?;\n\n                        stream.write_packet(&*payload)?;\n                        stream.flush().await?;\n\n                        Ok(false)\n                    }\n\n                    v => {\n                        Err(err_protocol!(\"unexpected result from fast authentication 0x{:x} when expecting 0x03 (AUTH_OK) or 0x04 (AUTH_CONTINUE)\", v))\n                    }\n                }\n            }\n\n            _ => Err(err_protocol!(\n                \"unexpected packet 0x{:02x} for auth plugin '{}' during authentication\",\n                packet[0],\n                self.name()\n            )),\n        }\n    }\n}\n\nfn scramble_sha1(\n    password: &str,\n    nonce: &Chain<Bytes, Bytes>,\n) -> GenericArray<u8, <Sha1 as OutputSizeUser>::OutputSize> {\n    // SHA1( password ) ^ SHA1( seed + SHA1( SHA1( password ) ) )\n    // https://mariadb.com/kb/en/connection/#mysql_native_password-plugin\n\n    let mut ctx = Sha1::new();\n\n    ctx.update(password);\n\n    let mut pw_hash = ctx.finalize_reset();\n\n    ctx.update(pw_hash);\n\n    let pw_hash_hash = ctx.finalize_reset();\n\n    ctx.update(nonce.first_ref());\n    ctx.update(nonce.last_ref());\n    ctx.update(pw_hash_hash);\n\n    let pw_seed_hash_hash = ctx.finalize();\n\n    xor_eq(&mut pw_hash, &pw_seed_hash_hash);\n\n    pw_hash\n}\n\nfn scramble_sha256(\n    password: &str,\n    nonce: &Chain<Bytes, Bytes>,\n) -> GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize> {\n    // XOR(SHA256(password), SHA256(seed, SHA256(SHA256(password))))\n    // https://mariadb.com/kb/en/caching_sha2_password-authentication-plugin/#sha-2-encrypted-password\n    let mut ctx = Sha256::new();\n\n    ctx.update(password);\n\n    let mut pw_hash = ctx.finalize_reset();\n\n    ctx.update(pw_hash);\n\n    let pw_hash_hash = ctx.finalize_reset();\n\n    ctx.update(nonce.first_ref());\n    ctx.update(nonce.last_ref());\n    ctx.update(pw_hash_hash);\n\n    let pw_seed_hash_hash = ctx.finalize();\n\n    xor_eq(&mut pw_hash, &pw_seed_hash_hash);\n\n    pw_hash\n}\n\nasync fn encrypt_rsa<'s>(\n    stream: &'s mut MySqlStream,\n    public_key_request_id: u8,\n    password: &'s str,\n    nonce: &'s Chain<Bytes, Bytes>,\n) -> Result<Vec<u8>, Error> {\n    // https://mariadb.com/kb/en/caching_sha2_password-authentication-plugin/\n\n    if stream.is_tls {\n        // If in a TLS stream, send the password directly in clear text\n        return Ok(to_asciz(password));\n    }\n\n    // client sends a public key request\n    stream.write_packet(&[public_key_request_id][..])?;\n    stream.flush().await?;\n\n    // server sends a public key response\n    let packet = stream.recv_packet().await?;\n    let rsa_pub_key = &packet[1..];\n\n    // xor the password with the given nonce\n    let mut pass = to_asciz(password);\n\n    let (a, b) = (nonce.first_ref(), nonce.last_ref());\n    let mut nonce = Vec::with_capacity(a.len() + b.len());\n    nonce.extend_from_slice(a);\n    nonce.extend_from_slice(b);\n\n    xor_eq(&mut pass, &nonce);\n\n    // client sends an RSA encrypted password\n    let pkey = parse_rsa_pub_key(rsa_pub_key)?;\n    let padding = Oaep::new::<sha1::Sha1>();\n    pkey.encrypt(&mut thread_rng(), padding, &pass[..])\n        .map_err(Error::protocol)\n}\n\n// XOR(x, y)\n// If len(y) < len(x), wrap around inside y\nfn xor_eq(x: &mut [u8], y: &[u8]) {\n    let y_len = y.len();\n\n    for i in 0..x.len() {\n        x[i] ^= y[i % y_len];\n    }\n}\n\nfn to_asciz(s: &str) -> Vec<u8> {\n    let mut z = String::with_capacity(s.len() + 1);\n    z.push_str(s);\n    z.push('\\0');\n\n    z.into_bytes()\n}\n\n// https://docs.rs/rsa/0.3.0/rsa/struct.RSAPublicKey.html?search=#example-1\nfn parse_rsa_pub_key(key: &[u8]) -> Result<RsaPublicKey, Error> {\n    let pem = std::str::from_utf8(key).map_err(Error::protocol)?;\n\n    // This takes advantage of the knowledge that we know\n    // we are receiving a PKCS#8 RSA Public Key at all\n    // times from MySQL\n\n    RsaPublicKey::from_public_key_pem(pem).map_err(Error::protocol)\n}\n"
  },
  {
    "path": "sqlx-mysql/src/connection/establish.rs",
    "content": "use bytes::buf::Buf;\nuse bytes::Bytes;\n\nuse crate::common::StatementCache;\nuse crate::connection::{tls, MySqlConnectionInner, MySqlStream, MAX_PACKET_SIZE};\nuse crate::error::Error;\nuse crate::net::{Socket, WithSocket};\nuse crate::protocol::connect::{\n    AuthSwitchRequest, AuthSwitchResponse, Handshake, HandshakeResponse,\n};\nuse crate::protocol::Capabilities;\nuse crate::{MySqlConnectOptions, MySqlConnection, MySqlSslMode};\n\nimpl MySqlConnection {\n    pub(crate) async fn establish(options: &MySqlConnectOptions) -> Result<Self, Error> {\n        let do_handshake = DoHandshake::new(options)?;\n\n        let handshake = match &options.socket {\n            Some(path) => crate::net::connect_uds(path, do_handshake).await?,\n            None => crate::net::connect_tcp(&options.host, options.port, do_handshake).await?,\n        };\n\n        let stream = handshake?;\n\n        Ok(Self {\n            inner: Box::new(MySqlConnectionInner {\n                stream,\n                transaction_depth: 0,\n                status_flags: Default::default(),\n                cache_statement: StatementCache::new(options.statement_cache_capacity),\n                log_settings: options.log_settings.clone(),\n            }),\n        })\n    }\n}\n\nstruct DoHandshake<'a> {\n    options: &'a MySqlConnectOptions,\n}\n\nimpl<'a> DoHandshake<'a> {\n    fn new(options: &'a MySqlConnectOptions) -> Result<Self, Error> {\n        if options.enable_cleartext_plugin\n            && matches!(\n                options.ssl_mode,\n                MySqlSslMode::Disabled | MySqlSslMode::Preferred\n            )\n        {\n            log::warn!(\"Security warning: sending cleartext passwords without requiring SSL\");\n        }\n\n        Ok(Self { options })\n    }\n\n    async fn do_handshake<S: Socket>(self, socket: S) -> Result<MySqlStream, Error> {\n        let DoHandshake { options } = self;\n\n        let mut stream = MySqlStream::with_socket(options, socket);\n\n        // https://dev.mysql.com/doc/internals/en/connection-phase.html\n        // https://mariadb.com/kb/en/connection/\n\n        let handshake: Handshake = stream.recv_packet().await?.decode()?;\n\n        let mut plugin = handshake.auth_plugin;\n        let nonce = handshake.auth_plugin_data;\n\n        // FIXME: server version parse is a bit ugly\n        // expecting MAJOR.MINOR.PATCH\n\n        let mut server_version = handshake.server_version.split('.');\n\n        let server_version_major: u16 = server_version\n            .next()\n            .unwrap_or_default()\n            .parse()\n            .unwrap_or(0);\n\n        let server_version_minor: u16 = server_version\n            .next()\n            .unwrap_or_default()\n            .parse()\n            .unwrap_or(0);\n\n        let server_version_patch: u16 = server_version\n            .next()\n            .unwrap_or_default()\n            .parse()\n            .unwrap_or(0);\n\n        stream.server_version = (\n            server_version_major,\n            server_version_minor,\n            server_version_patch,\n        );\n\n        stream.capabilities &= handshake.server_capabilities;\n        stream.capabilities |= Capabilities::PROTOCOL_41;\n\n        let mut stream = tls::maybe_upgrade(stream, self.options).await?;\n\n        let auth_response = if let (Some(plugin), Some(password)) = (plugin, &options.password) {\n            Some(plugin.scramble(&mut stream, password, &nonce).await?)\n        } else {\n            None\n        };\n\n        stream.write_packet(HandshakeResponse {\n            charset: super::INITIAL_CHARSET,\n            max_packet_size: MAX_PACKET_SIZE,\n            username: &options.username,\n            database: options.database.as_deref(),\n            auth_plugin: plugin,\n            auth_response: auth_response.as_deref(),\n        })?;\n\n        stream.flush().await?;\n\n        loop {\n            let packet = stream.recv_packet().await?;\n            match packet[0] {\n                0x00 => {\n                    let _ok = packet.ok()?;\n\n                    break;\n                }\n\n                0xfe => {\n                    let switch: AuthSwitchRequest =\n                        packet.decode_with(self.options.enable_cleartext_plugin)?;\n\n                    plugin = Some(switch.plugin);\n                    let nonce = switch.data.chain(Bytes::new());\n\n                    let response = switch\n                        .plugin\n                        .scramble(\n                            &mut stream,\n                            options.password.as_deref().unwrap_or_default(),\n                            &nonce,\n                        )\n                        .await?;\n\n                    stream.write_packet(AuthSwitchResponse(response))?;\n                    stream.flush().await?;\n                }\n\n                id => {\n                    if let (Some(plugin), Some(password)) = (plugin, &options.password) {\n                        if plugin.handle(&mut stream, packet, password, &nonce).await? {\n                            // plugin signaled authentication is ok\n                            break;\n                        }\n\n                        // plugin signaled to continue authentication\n                    } else {\n                        return Err(err_protocol!(\n                            \"unexpected packet 0x{:02x} during authentication\",\n                            id\n                        ));\n                    }\n                }\n            }\n        }\n\n        Ok(stream)\n    }\n}\n\nimpl WithSocket for DoHandshake<'_> {\n    type Output = Result<MySqlStream, Error>;\n\n    async fn with_socket<S: Socket>(self, socket: S) -> Self::Output {\n        self.do_handshake(socket).await\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/connection/executor.rs",
    "content": "use super::MySqlStream;\nuse crate::connection::stream::Waiting;\nuse crate::error::Error;\nuse crate::executor::{Execute, Executor};\nuse crate::ext::ustr::UStr;\nuse crate::io::MySqlBufExt;\nuse crate::logger::QueryLogger;\nuse crate::protocol::response::Status;\nuse crate::protocol::statement::{\n    BinaryRow, Execute as StatementExecute, Prepare, PrepareOk, StmtClose,\n};\nuse crate::protocol::text::{ColumnDefinition, Query, TextRow};\nuse crate::statement::{MySqlStatement, MySqlStatementMetadata};\nuse crate::HashMap;\nuse crate::{\n    MySql, MySqlArguments, MySqlColumn, MySqlConnection, MySqlQueryResult, MySqlRow, MySqlTypeInfo,\n    MySqlValueFormat,\n};\nuse either::Either;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_core::Stream;\nuse futures_util::TryStreamExt;\nuse sqlx_core::column::{ColumnOrigin, TableColumn};\nuse sqlx_core::sql_str::SqlStr;\nuse std::{pin::pin, sync::Arc};\n\nimpl MySqlConnection {\n    async fn prepare_statement(\n        &mut self,\n        sql: &str,\n    ) -> Result<(u32, MySqlStatementMetadata), Error> {\n        // https://dev.mysql.com/doc/internals/en/com-stmt-prepare.html\n        // https://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html#packet-COM_STMT_PREPARE_OK\n\n        self.inner\n            .stream\n            .send_packet(Prepare { query: sql })\n            .await?;\n\n        let ok: PrepareOk = self.inner.stream.recv().await?;\n\n        // the parameter definitions are very unreliable so we skip over them\n        // as we have little use\n\n        if ok.params > 0 {\n            for _ in 0..ok.params {\n                let _def: ColumnDefinition = self.inner.stream.recv().await?;\n            }\n\n            self.inner.stream.maybe_recv_eof().await?;\n        }\n\n        // the column definitions are berefit the type information from the\n        // to-be-bound parameters; we will receive the output column definitions\n        // once more on execute so we wait for that\n\n        let mut columns = Vec::new();\n\n        let column_names = if ok.columns > 0 {\n            recv_result_metadata(&mut self.inner.stream, ok.columns as usize, &mut columns).await?\n        } else {\n            Default::default()\n        };\n\n        let id = ok.statement_id;\n        let metadata = MySqlStatementMetadata {\n            parameters: ok.params as usize,\n            columns: Arc::new(columns),\n            column_names: Arc::new(column_names),\n        };\n\n        Ok((id, metadata))\n    }\n\n    async fn get_or_prepare_statement(\n        &mut self,\n        sql: &str,\n    ) -> Result<(u32, MySqlStatementMetadata), Error> {\n        if let Some(statement) = self.inner.cache_statement.get_mut(sql) {\n            // <MySqlStatementMetadata> is internally reference-counted\n            return Ok((*statement).clone());\n        }\n\n        let (id, metadata) = self.prepare_statement(sql).await?;\n\n        // in case of the cache being full, close the least recently used statement\n        if let Some((id, _)) = self\n            .inner\n            .cache_statement\n            .insert(sql, (id, metadata.clone()))\n        {\n            self.inner\n                .stream\n                .send_packet(StmtClose { statement: id })\n                .await?;\n        }\n\n        Ok((id, metadata))\n    }\n\n    #[allow(clippy::needless_lifetimes)]\n    pub(crate) async fn run<'e, 'c: 'e, 'q: 'e>(\n        &'c mut self,\n        sql: SqlStr,\n        arguments: Option<MySqlArguments>,\n        persistent: bool,\n    ) -> Result<impl Stream<Item = Result<Either<MySqlQueryResult, MySqlRow>, Error>> + 'e, Error>\n    {\n        let mut logger = QueryLogger::new(sql, self.inner.log_settings.clone());\n\n        self.inner.stream.wait_until_ready().await?;\n        self.inner.stream.waiting.push_back(Waiting::Result);\n\n        Ok(try_stream! {\n        let sql = logger.sql().as_str();\n\n            // make a slot for the shared column data\n            // as long as a reference to a row is not held past one iteration, this enables us\n            // to re-use this memory freely between result sets\n            let mut columns = Arc::new(Vec::new());\n\n            let (mut column_names, format, mut needs_metadata) = if let Some(arguments) = arguments {\n                if persistent && self.inner.cache_statement.is_enabled() {\n                    let (id, metadata) = self\n                        .get_or_prepare_statement(sql)\n                        .await?;\n\n                    if arguments.types.len() != metadata.parameters {\n                        return Err(\n                            err_protocol!(\n                                \"prepared statement expected {} parameters but {} parameters were provided\",\n                                metadata.parameters,\n                                arguments.types.len()\n                            )\n                        );\n                    }\n\n                    // https://dev.mysql.com/doc/internals/en/com-stmt-execute.html\n                    self.inner.stream\n                        .send_packet(StatementExecute {\n                            statement: id,\n                            arguments: &arguments,\n                        })\n                        .await?;\n\n                    (metadata.column_names, MySqlValueFormat::Binary, false)\n                } else {\n                    let (id, metadata) = self\n                        .prepare_statement(sql)\n                        .await?;\n\n                    if arguments.types.len() != metadata.parameters {\n                        return Err(\n                            err_protocol!(\n                                \"prepared statement expected {} parameters but {} parameters were provided\",\n                                metadata.parameters,\n                                arguments.types.len()\n                            )\n                        );\n                    }\n\n                    // https://dev.mysql.com/doc/internals/en/com-stmt-execute.html\n                    self.inner.stream\n                        .send_packet(StatementExecute {\n                            statement: id,\n                            arguments: &arguments,\n                        })\n                        .await?;\n\n                    self.inner.stream.send_packet(StmtClose { statement: id }).await?;\n\n                    (metadata.column_names, MySqlValueFormat::Binary, false)\n                }\n            } else {\n                // https://dev.mysql.com/doc/internals/en/com-query.html\n                self.inner.stream.send_packet(Query(sql)).await?;\n\n                (Arc::default(), MySqlValueFormat::Text, true)\n            };\n\n            loop {\n                // query response is a meta-packet which may be one of:\n                //  Ok, Err, ResultSet, or (unhandled) LocalInfileRequest\n                let mut packet = self.inner.stream.recv_packet().await?;\n\n                if packet[0] == 0x00 || packet[0] == 0xff {\n                    // first packet in a query response is OK or ERR\n                    // this indicates either a successful query with no rows at all or a failed query\n                    let ok = packet.ok()?;\n\n                    self.inner.status_flags = ok.status;\n\n                    let rows_affected = ok.affected_rows;\n                    logger.increase_rows_affected(rows_affected);\n                    let done = MySqlQueryResult {\n                        rows_affected,\n                        last_insert_id: ok.last_insert_id,\n                    };\n\n                    r#yield!(Either::Left(done));\n\n                    if ok.status.contains(Status::SERVER_MORE_RESULTS_EXISTS) {\n                        // more result sets exist, continue to the next one\n                        continue;\n                    }\n\n                    self.inner.stream.waiting.pop_front();\n                    return Ok(());\n                }\n\n                // otherwise, this first packet is the start of the result-set metadata,\n                *self.inner.stream.waiting.front_mut().unwrap() = Waiting::Row;\n\n                let num_columns = packet.get_uint_lenenc()?; // column count\n                let num_columns = usize::try_from(num_columns)\n                    .map_err(|_| err_protocol!(\"column count overflows usize: {num_columns}\"))?;\n\n                if needs_metadata {\n                    column_names = Arc::new(recv_result_metadata(&mut self.inner.stream, num_columns, Arc::make_mut(&mut columns)).await?);\n                } else {\n                    // next time we hit here, it'll be a new result set and we'll need the\n                    // full metadata\n                    needs_metadata = true;\n\n                    recv_result_columns(&mut self.inner.stream, num_columns, Arc::make_mut(&mut columns)).await?;\n                }\n\n                // finally, there will be none or many result-rows\n                loop {\n                    let packet = self.inner.stream.recv_packet().await?;\n\n                    if packet[0] == 0xfe {\n                        let (rows_affected, last_insert_id, status) = if packet.len() < 9 {\n                            // EOF packet\n                            let eof = packet.eof(self.inner.stream.capabilities)?;\n                            (0, 0, eof.status)\n                        } else {\n                            // OK packet\n                            let ok = packet.ok()?;\n                            (ok.affected_rows, ok.last_insert_id, ok.status)\n                        };\n\n                        self.inner.status_flags = status;\n                        r#yield!(Either::Left(MySqlQueryResult {\n                            rows_affected,\n                            last_insert_id,\n                        }));\n\n                        if status.contains(Status::SERVER_MORE_RESULTS_EXISTS) {\n                            *self.inner.stream.waiting.front_mut().unwrap() = Waiting::Result;\n                            break;\n                        }\n                        self.inner.stream.waiting.pop_front();\n                        return Ok(());\n                    }\n\n                    let row = match format {\n                        MySqlValueFormat::Binary => packet.decode_with::<BinaryRow, _>(&columns)?.0,\n                        MySqlValueFormat::Text => packet.decode_with::<TextRow, _>(&columns)?.0,\n                    };\n\n                    let v = Either::Right(MySqlRow {\n                        row,\n                        format,\n                        columns: Arc::clone(&columns),\n                        column_names: Arc::clone(&column_names),\n                    });\n\n                    logger.increment_rows_returned();\n\n                    r#yield!(v);\n                }\n            }\n        })\n    }\n}\n\nimpl<'c> Executor<'c> for &'c mut MySqlConnection {\n    type Database = MySql;\n\n    fn fetch_many<'e, 'q, E>(\n        self,\n        mut query: E,\n    ) -> BoxStream<'e, Result<Either<MySqlQueryResult, MySqlRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        let arguments = query.take_arguments().map_err(Error::Encode);\n        let persistent = query.persistent();\n\n        Box::pin(try_stream! {\n        let sql = query.sql();\n            let arguments = arguments?;\n            let mut s = pin!(self.run(sql, arguments, persistent).await?);\n\n            while let Some(v) = s.try_next().await? {\n                r#yield!(v);\n            }\n\n            Ok(())\n        })\n    }\n\n    fn fetch_optional<'e, 'q, E>(self, query: E) -> BoxFuture<'e, Result<Option<MySqlRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        let mut s = self.fetch_many(query);\n\n        Box::pin(async move {\n            while let Some(v) = s.try_next().await? {\n                if let Either::Right(r) = v {\n                    return Ok(Some(r));\n                }\n            }\n\n            Ok(None)\n        })\n    }\n\n    fn prepare_with<'e>(\n        self,\n        sql: SqlStr,\n        _parameters: &'e [MySqlTypeInfo],\n    ) -> BoxFuture<'e, Result<MySqlStatement, Error>>\n    where\n        'c: 'e,\n    {\n        Box::pin(async move {\n            self.inner.stream.wait_until_ready().await?;\n\n            let metadata = if self.inner.cache_statement.is_enabled() {\n                self.get_or_prepare_statement(sql.as_str()).await?.1\n            } else {\n                let (id, metadata) = self.prepare_statement(sql.as_str()).await?;\n\n                self.inner\n                    .stream\n                    .send_packet(StmtClose { statement: id })\n                    .await?;\n\n                metadata\n            };\n\n            Ok(MySqlStatement {\n                sql,\n                // metadata has internal Arcs for expensive data structures\n                metadata: metadata.clone(),\n            })\n        })\n    }\n\n    #[doc(hidden)]\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        sql: SqlStr,\n    ) -> BoxFuture<'e, Result<crate::describe::Describe<MySql>, Error>>\n    where\n        'c: 'e,\n    {\n        Box::pin(async move {\n            self.inner.stream.wait_until_ready().await?;\n\n            let (id, metadata) = self.prepare_statement(sql.as_str()).await?;\n\n            self.inner\n                .stream\n                .send_packet(StmtClose { statement: id })\n                .await?;\n\n            let columns = (*metadata.columns).clone();\n\n            let nullable = columns\n                .iter()\n                .map(|col| {\n                    col.flags\n                        .map(|flags| !flags.contains(crate::protocol::text::ColumnFlags::NOT_NULL))\n                })\n                .collect();\n\n            Ok(crate::describe::Describe {\n                parameters: Some(Either::Right(metadata.parameters)),\n                columns,\n                nullable,\n            })\n        })\n    }\n}\n\nasync fn recv_result_columns(\n    stream: &mut MySqlStream,\n    num_columns: usize,\n    columns: &mut Vec<MySqlColumn>,\n) -> Result<(), Error> {\n    columns.clear();\n    columns.reserve(num_columns);\n\n    for ordinal in 0..num_columns {\n        columns.push(recv_next_result_column(&stream.recv().await?, ordinal)?);\n    }\n\n    if num_columns > 0 {\n        stream.maybe_recv_eof().await?;\n    }\n\n    Ok(())\n}\n\nfn recv_next_result_column(def: &ColumnDefinition, ordinal: usize) -> Result<MySqlColumn, Error> {\n    // if the alias is empty, use the alias\n    // only then use the name\n    let column_name = def.name()?;\n\n    let name = match (def.name()?, def.alias()?) {\n        (_, alias) if !alias.is_empty() => UStr::new(alias),\n        (name, _) => UStr::new(name),\n    };\n\n    let table = def.table()?;\n\n    let origin = if table.is_empty() {\n        ColumnOrigin::Expression\n    } else {\n        let schema = def.schema()?;\n\n        ColumnOrigin::Table(TableColumn {\n            table: if !schema.is_empty() {\n                format!(\"{schema}.{table}\").into()\n            } else {\n                table.into()\n            },\n            name: column_name.into(),\n        })\n    };\n\n    let type_info = MySqlTypeInfo::from_column(def);\n\n    Ok(MySqlColumn {\n        name,\n        type_info,\n        ordinal,\n        flags: Some(def.flags),\n        origin,\n    })\n}\n\nasync fn recv_result_metadata(\n    stream: &mut MySqlStream,\n    num_columns: usize,\n    columns: &mut Vec<MySqlColumn>,\n) -> Result<HashMap<UStr, usize>, Error> {\n    // the result-set metadata is primarily a listing of each output\n    // column in the result-set\n\n    let mut column_names = HashMap::with_capacity(num_columns);\n\n    columns.clear();\n    columns.reserve(num_columns);\n\n    for ordinal in 0..num_columns {\n        let def: ColumnDefinition = stream.recv().await?;\n\n        let column = recv_next_result_column(&def, ordinal)?;\n\n        column_names.insert(column.name.clone(), ordinal);\n        columns.push(column);\n    }\n\n    stream.maybe_recv_eof().await?;\n\n    Ok(column_names)\n}\n"
  },
  {
    "path": "sqlx-mysql/src/connection/mod.rs",
    "content": "use std::fmt::{self, Debug, Formatter};\nuse std::future::Future;\n\npub(crate) use sqlx_core::connection::*;\nuse sqlx_core::sql_str::SqlSafeStr;\npub(crate) use stream::{MySqlStream, Waiting};\n\nuse crate::collation::Collation;\nuse crate::common::StatementCache;\nuse crate::error::Error;\nuse crate::protocol::response::Status;\nuse crate::protocol::statement::StmtClose;\nuse crate::protocol::text::{Ping, Quit};\nuse crate::statement::MySqlStatementMetadata;\nuse crate::transaction::Transaction;\nuse crate::{MySql, MySqlConnectOptions};\n\nmod auth;\nmod establish;\nmod executor;\nmod stream;\nmod tls;\n\nconst MAX_PACKET_SIZE: u32 = 1024;\n\n/// The charset parameter sent in the `Protocol::HandshakeResponse41` packet.\n///\n/// This becomes the default if `set_names = false`,\n/// and also ensures that any error messages returned before `SET NAMES` are encoded correctly.\n#[allow(clippy::cast_possible_truncation)]\nconst INITIAL_CHARSET: u8 = Collation::UTF8MB4_GENERAL_CI.0 as u8;\n\n/// A connection to a MySQL database.\npub struct MySqlConnection {\n    pub(crate) inner: Box<MySqlConnectionInner>,\n}\n\npub(crate) struct MySqlConnectionInner {\n    // underlying TCP stream,\n    // wrapped in a potentially TLS stream,\n    // wrapped in a buffered stream\n    pub(crate) stream: MySqlStream,\n\n    // transaction status\n    pub(crate) transaction_depth: usize,\n    status_flags: Status,\n\n    // cache by query string to the statement id and metadata\n    cache_statement: StatementCache<(u32, MySqlStatementMetadata)>,\n\n    log_settings: LogSettings,\n}\n\nimpl MySqlConnection {\n    pub(crate) fn in_transaction(&self) -> bool {\n        self.inner\n            .status_flags\n            .intersects(Status::SERVER_STATUS_IN_TRANS)\n    }\n}\n\nimpl Debug for MySqlConnection {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"MySqlConnection\").finish()\n    }\n}\n\nimpl Connection for MySqlConnection {\n    type Database = MySql;\n\n    type Options = MySqlConnectOptions;\n\n    async fn close(mut self) -> Result<(), Error> {\n        self.inner.stream.send_packet(Quit).await?;\n        self.inner.stream.shutdown().await?;\n\n        Ok(())\n    }\n\n    async fn close_hard(mut self) -> Result<(), Error> {\n        self.inner.stream.shutdown().await?;\n        Ok(())\n    }\n\n    async fn ping(&mut self) -> Result<(), Error> {\n        self.inner.stream.wait_until_ready().await?;\n        self.inner.stream.send_packet(Ping).await?;\n        self.inner.stream.recv_ok().await?;\n\n        Ok(())\n    }\n\n    #[doc(hidden)]\n    fn flush(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        self.inner.stream.wait_until_ready()\n    }\n\n    fn cached_statements_size(&self) -> usize {\n        self.inner.cache_statement.len()\n    }\n\n    async fn clear_cached_statements(&mut self) -> Result<(), Error> {\n        while let Some((statement_id, _)) = self.inner.cache_statement.remove_lru() {\n            self.inner\n                .stream\n                .send_packet(StmtClose {\n                    statement: statement_id,\n                })\n                .await?;\n        }\n\n        Ok(())\n    }\n\n    #[doc(hidden)]\n    fn should_flush(&self) -> bool {\n        !self.inner.stream.write_buffer().is_empty()\n    }\n\n    fn begin(\n        &mut self,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_ {\n        Transaction::begin(self, None)\n    }\n\n    fn begin_with(\n        &mut self,\n        statement: impl SqlSafeStr,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        Transaction::begin(self, Some(statement.into_sql_str()))\n    }\n\n    fn shrink_buffers(&mut self) {\n        self.inner.stream.shrink_buffers();\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/connection/stream.rs",
    "content": "use std::collections::VecDeque;\nuse std::ops::{Deref, DerefMut};\n\nuse bytes::{Buf, Bytes, BytesMut};\n\nuse crate::error::Error;\nuse crate::io::MySqlBufExt;\nuse crate::io::{ProtocolDecode, ProtocolEncode};\nuse crate::net::{BufferedSocket, Socket};\nuse crate::protocol::response::{EofPacket, ErrPacket, OkPacket, Status};\nuse crate::protocol::{Capabilities, Packet};\nuse crate::{MySqlConnectOptions, MySqlDatabaseError};\n\npub struct MySqlStream<S = Box<dyn Socket>> {\n    // Wrapping the socket in `Box` allows us to unsize in-place.\n    pub(crate) socket: BufferedSocket<S>,\n    pub(crate) server_version: (u16, u16, u16),\n    pub(super) capabilities: Capabilities,\n    pub(crate) sequence_id: u8,\n    pub(crate) waiting: VecDeque<Waiting>,\n    pub(crate) is_tls: bool,\n}\n\n#[derive(Debug, PartialEq, Eq)]\npub(crate) enum Waiting {\n    // waiting for a result set\n    Result,\n\n    // waiting for a row within a result set\n    Row,\n}\n\nimpl<S: Socket> MySqlStream<S> {\n    pub(crate) fn with_socket(options: &MySqlConnectOptions, socket: S) -> Self {\n        let mut capabilities = Capabilities::PROTOCOL_41\n            | Capabilities::IGNORE_SPACE\n            | Capabilities::DEPRECATE_EOF\n            | Capabilities::FOUND_ROWS\n            | Capabilities::TRANSACTIONS\n            | Capabilities::SECURE_CONNECTION\n            | Capabilities::PLUGIN_AUTH_LENENC_DATA\n            | Capabilities::MULTI_STATEMENTS\n            | Capabilities::MULTI_RESULTS\n            | Capabilities::PLUGIN_AUTH\n            | Capabilities::PS_MULTI_RESULTS\n            | Capabilities::SSL;\n\n        if options.database.is_some() {\n            capabilities |= Capabilities::CONNECT_WITH_DB;\n        }\n\n        Self {\n            waiting: VecDeque::new(),\n            capabilities,\n            server_version: (0, 0, 0),\n            sequence_id: 0,\n            socket: BufferedSocket::new(socket),\n            is_tls: false,\n        }\n    }\n\n    pub(crate) async fn wait_until_ready(&mut self) -> Result<(), Error> {\n        if !self.socket.write_buffer().is_empty() {\n            self.socket.flush().await?;\n        }\n\n        while !self.waiting.is_empty() {\n            while self.waiting.front() == Some(&Waiting::Row) {\n                let packet = self.recv_packet().await?;\n\n                if !packet.is_empty() && packet[0] == 0xfe && packet.len() < 9 {\n                    let eof = packet.eof(self.capabilities)?;\n\n                    if eof.status.contains(Status::SERVER_MORE_RESULTS_EXISTS) {\n                        *self.waiting.front_mut().unwrap() = Waiting::Result;\n                    } else {\n                        self.waiting.pop_front();\n                    };\n                }\n            }\n\n            while self.waiting.front() == Some(&Waiting::Result) {\n                let packet = self.recv_packet().await?;\n\n                if !packet.is_empty() && (packet[0] == 0x00 || packet[0] == 0xff) {\n                    let ok = packet.ok()?;\n\n                    if !ok.status.contains(Status::SERVER_MORE_RESULTS_EXISTS) {\n                        self.waiting.pop_front();\n                    }\n                } else {\n                    *self.waiting.front_mut().unwrap() = Waiting::Row;\n                    self.skip_result_metadata(packet).await?;\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    pub(crate) async fn send_packet<'en, T>(&mut self, payload: T) -> Result<(), Error>\n    where\n        T: ProtocolEncode<'en, Capabilities>,\n    {\n        self.sequence_id = 0;\n        self.write_packet(payload)?;\n        self.flush().await?;\n        Ok(())\n    }\n\n    pub(crate) fn write_packet<'en, T>(&mut self, payload: T) -> Result<(), Error>\n    where\n        T: ProtocolEncode<'en, Capabilities>,\n    {\n        self.socket\n            .write_with(Packet(payload), (self.capabilities, &mut self.sequence_id))\n    }\n\n    async fn recv_packet_part(&mut self) -> Result<Bytes, Error> {\n        // https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_basic_packets.html\n        // https://mariadb.com/kb/en/library/0-packet/#standard-packet\n\n        let mut header: Bytes = self.socket.read(4).await?;\n\n        // cannot overflow\n        #[allow(clippy::cast_possible_truncation)]\n        let packet_size = header.get_uint_le(3) as usize;\n        let sequence_id = header.get_u8();\n\n        self.sequence_id = sequence_id.wrapping_add(1);\n\n        let payload: Bytes = self.socket.read(packet_size).await?;\n\n        // TODO: packet compression\n\n        Ok(payload)\n    }\n\n    // receive the next packet from the database server\n    // may block (async) on more data from the server\n    pub(crate) async fn recv_packet(&mut self) -> Result<Packet<Bytes>, Error> {\n        let payload = self.recv_packet_part().await?;\n        let payload = if payload.len() < 0xFF_FF_FF {\n            payload\n        } else {\n            let mut final_payload = BytesMut::with_capacity(0xFF_FF_FF * 2);\n            final_payload.extend_from_slice(&payload);\n\n            drop(payload); // we don't need the allocation anymore\n\n            let mut last_read = 0xFF_FF_FF;\n            while last_read == 0xFF_FF_FF {\n                let part = self.recv_packet_part().await?;\n                last_read = part.len();\n                final_payload.extend_from_slice(&part);\n            }\n            final_payload.into()\n        };\n\n        if payload\n            .first()\n            .ok_or(err_protocol!(\"Packet empty\"))?\n            .eq(&0xff)\n        {\n            self.waiting.pop_front();\n\n            // instead of letting this packet be looked at everywhere, we check here\n            // and emit a proper Error\n            return Err(\n                MySqlDatabaseError(ErrPacket::decode_with(payload, self.capabilities)?).into(),\n            );\n        }\n\n        Ok(Packet(payload))\n    }\n\n    pub(crate) async fn recv<'de, T>(&mut self) -> Result<T, Error>\n    where\n        T: ProtocolDecode<'de, Capabilities>,\n    {\n        self.recv_packet().await?.decode_with(self.capabilities)\n    }\n\n    pub(crate) async fn recv_ok(&mut self) -> Result<OkPacket, Error> {\n        self.recv_packet().await?.ok()\n    }\n\n    pub(crate) async fn maybe_recv_eof(&mut self) -> Result<Option<EofPacket>, Error> {\n        if self.capabilities.contains(Capabilities::DEPRECATE_EOF) {\n            Ok(None)\n        } else {\n            self.recv().await.map(Some)\n        }\n    }\n\n    async fn skip_result_metadata(&mut self, mut packet: Packet<Bytes>) -> Result<(), Error> {\n        let num_columns: u64 = packet.get_uint_lenenc()?; // column count\n\n        for _ in 0..num_columns {\n            let _ = self.recv_packet().await?;\n        }\n\n        self.maybe_recv_eof().await?;\n\n        Ok(())\n    }\n\n    pub fn boxed_socket(self) -> MySqlStream {\n        MySqlStream {\n            socket: self.socket.boxed(),\n            server_version: self.server_version,\n            capabilities: self.capabilities,\n            sequence_id: self.sequence_id,\n            waiting: self.waiting,\n            is_tls: self.is_tls,\n        }\n    }\n}\n\nimpl<S> Deref for MySqlStream<S> {\n    type Target = BufferedSocket<S>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.socket\n    }\n}\n\nimpl<S> DerefMut for MySqlStream<S> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.socket\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/connection/tls.rs",
    "content": "use crate::connection::{MySqlStream, Waiting};\nuse crate::error::Error;\nuse crate::net::tls::TlsConfig;\nuse crate::net::{tls, BufferedSocket, Socket, WithSocket};\nuse crate::protocol::connect::SslRequest;\nuse crate::protocol::Capabilities;\nuse crate::{MySqlConnectOptions, MySqlSslMode};\nuse std::collections::VecDeque;\n\nstruct MapStream {\n    server_version: (u16, u16, u16),\n    capabilities: Capabilities,\n    sequence_id: u8,\n    waiting: VecDeque<Waiting>,\n}\n\npub(super) async fn maybe_upgrade<S: Socket>(\n    mut stream: MySqlStream<S>,\n    options: &MySqlConnectOptions,\n) -> Result<MySqlStream, Error> {\n    let server_supports_tls = stream.capabilities.contains(Capabilities::SSL);\n\n    if matches!(options.ssl_mode, MySqlSslMode::Disabled) || !tls::available() {\n        // remove the SSL capability if SSL has been explicitly disabled\n        stream.capabilities.remove(Capabilities::SSL);\n    }\n\n    // https://www.postgresql.org/docs/12/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS\n    match options.ssl_mode {\n        MySqlSslMode::Disabled => return Ok(stream.boxed_socket()),\n\n        MySqlSslMode::Preferred => {\n            if !tls::available() {\n                // Client doesn't support TLS\n                tracing::debug!(\"not performing TLS upgrade: TLS support not compiled in\");\n                return Ok(stream.boxed_socket());\n            }\n\n            if !server_supports_tls {\n                // Server doesn't support TLS\n                tracing::debug!(\"not performing TLS upgrade: unsupported by server\");\n                return Ok(stream.boxed_socket());\n            }\n        }\n\n        MySqlSslMode::Required | MySqlSslMode::VerifyIdentity | MySqlSslMode::VerifyCa => {\n            tls::error_if_unavailable()?;\n\n            if !server_supports_tls {\n                // upgrade failed, die\n                return Err(Error::Tls(\"server does not support TLS\".into()));\n            }\n        }\n    }\n\n    let tls_config = TlsConfig {\n        accept_invalid_certs: !matches!(\n            options.ssl_mode,\n            MySqlSslMode::VerifyCa | MySqlSslMode::VerifyIdentity\n        ),\n        accept_invalid_hostnames: !matches!(options.ssl_mode, MySqlSslMode::VerifyIdentity),\n        hostname: &options.host,\n        root_cert_path: options.ssl_ca.as_ref(),\n        client_cert_path: options.ssl_client_cert.as_ref(),\n        client_key_path: options.ssl_client_key.as_ref(),\n    };\n\n    // Request TLS upgrade\n    stream.write_packet(SslRequest {\n        max_packet_size: super::MAX_PACKET_SIZE,\n        charset: super::INITIAL_CHARSET,\n    })?;\n\n    stream.flush().await?;\n\n    tls::handshake(\n        stream.socket.into_inner(),\n        tls_config,\n        MapStream {\n            server_version: stream.server_version,\n            capabilities: stream.capabilities,\n            sequence_id: stream.sequence_id,\n            waiting: stream.waiting,\n        },\n    )\n    .await\n}\n\nimpl WithSocket for MapStream {\n    type Output = MySqlStream;\n\n    async fn with_socket<S: Socket>(self, socket: S) -> Self::Output {\n        MySqlStream {\n            socket: BufferedSocket::new(Box::new(socket)),\n            server_version: self.server_version,\n            capabilities: self.capabilities,\n            sequence_id: self.sequence_id,\n            waiting: self.waiting,\n            is_tls: true,\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/database.rs",
    "content": "use crate::value::{MySqlValue, MySqlValueRef};\nuse crate::{\n    MySqlArguments, MySqlColumn, MySqlConnection, MySqlQueryResult, MySqlRow, MySqlStatement,\n    MySqlTransactionManager, MySqlTypeInfo,\n};\npub(crate) use sqlx_core::database::{Database, HasStatementCache};\n\n/// MySQL database driver.\n#[derive(Debug)]\npub struct MySql;\n\nimpl Database for MySql {\n    type Connection = MySqlConnection;\n\n    type TransactionManager = MySqlTransactionManager;\n\n    type Row = MySqlRow;\n\n    type QueryResult = MySqlQueryResult;\n\n    type Column = MySqlColumn;\n\n    type TypeInfo = MySqlTypeInfo;\n\n    type Value = MySqlValue;\n    type ValueRef<'r> = MySqlValueRef<'r>;\n\n    type Arguments = MySqlArguments;\n    type ArgumentBuffer = Vec<u8>;\n\n    type Statement = MySqlStatement;\n\n    const NAME: &'static str = \"MySQL\";\n\n    const URL_SCHEMES: &'static [&'static str] = &[\"mysql\", \"mariadb\"];\n}\n\nimpl HasStatementCache for MySql {}\n"
  },
  {
    "path": "sqlx-mysql/src/error.rs",
    "content": "use std::error::Error as StdError;\nuse std::fmt::{self, Debug, Display, Formatter};\n\nuse crate::protocol::response::ErrPacket;\n\nuse std::borrow::Cow;\n\npub(crate) use sqlx_core::error::*;\n\n/// An error returned from the MySQL database.\npub struct MySqlDatabaseError(pub(super) ErrPacket);\n\nimpl MySqlDatabaseError {\n    /// The [SQLSTATE](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html) code for this error.\n    pub fn code(&self) -> Option<&str> {\n        self.0.sql_state.as_deref()\n    }\n\n    /// The [number](https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html)\n    /// for this error.\n    ///\n    /// MySQL tends to use SQLSTATE as a general error category, and the error number as a more\n    /// granular indication of the error.\n    pub fn number(&self) -> u16 {\n        self.0.error_code\n    }\n\n    /// The human-readable error message.\n    pub fn message(&self) -> &str {\n        &self.0.error_message\n    }\n}\n\nimpl Debug for MySqlDatabaseError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"MySqlDatabaseError\")\n            .field(\"code\", &self.code())\n            .field(\"number\", &self.number())\n            .field(\"message\", &self.message())\n            .finish()\n    }\n}\n\nimpl Display for MySqlDatabaseError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        if let Some(code) = &self.code() {\n            write!(f, \"{} ({}): {}\", self.number(), code, self.message())\n        } else {\n            write!(f, \"{}: {}\", self.number(), self.message())\n        }\n    }\n}\n\nimpl StdError for MySqlDatabaseError {}\n\nimpl DatabaseError for MySqlDatabaseError {\n    #[inline]\n    fn message(&self) -> &str {\n        self.message()\n    }\n\n    #[inline]\n    fn code(&self) -> Option<Cow<'_, str>> {\n        self.code().map(Cow::Borrowed)\n    }\n\n    #[doc(hidden)]\n    fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {\n        self\n    }\n\n    #[doc(hidden)]\n    fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {\n        self\n    }\n\n    #[doc(hidden)]\n    fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static> {\n        self\n    }\n\n    fn kind(&self) -> ErrorKind {\n        match self.number() {\n            error_codes::ER_DUP_KEY\n            | error_codes::ER_DUP_ENTRY\n            | error_codes::ER_DUP_UNIQUE\n            | error_codes::ER_DUP_ENTRY_WITH_KEY_NAME\n            | error_codes::ER_DUP_UNKNOWN_IN_INDEX => ErrorKind::UniqueViolation,\n\n            error_codes::ER_NO_REFERENCED_ROW\n            | error_codes::ER_NO_REFERENCED_ROW_2\n            | error_codes::ER_ROW_IS_REFERENCED\n            | error_codes::ER_ROW_IS_REFERENCED_2\n            | error_codes::ER_FK_COLUMN_NOT_NULL\n            | error_codes::ER_FK_CANNOT_DELETE_PARENT => ErrorKind::ForeignKeyViolation,\n\n            error_codes::ER_BAD_NULL_ERROR | error_codes::ER_NO_DEFAULT_FOR_FIELD => {\n                ErrorKind::NotNullViolation\n            }\n\n            error_codes::ER_CHECK_CONSTRAINT_VIOLATED => ErrorKind::CheckViolation,\n\n            // https://mariadb.com/kb/en/e4025/\n            error_codes::mariadb::ER_CONSTRAINT_FAILED\n                // MySQL uses this code for a completely different error,\n                // but we can differentiate by SQLSTATE:\n                // <https://dev.mysql.com/doc/mysql-errors/8.4/en/server-error-reference.html#error_er_innodb_autoextend_size_out_of_range\n                if self.0.sql_state.as_deref() == Some(\"23000\") =>\n            {\n                ErrorKind::CheckViolation\n            }\n\n            _ => ErrorKind::Other,\n        }\n    }\n}\n\n/// The MySQL server uses SQLSTATEs as a generic error category,\n/// and returns a `error_code` instead within the error packet.\n///\n/// For reference: <https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html>.\npub(crate) mod error_codes {\n    /// Caused when a DDL operation creates duplicated keys.\n    pub const ER_DUP_KEY: u16 = 1022;\n    /// Caused when a DML operation tries create a duplicated entry for a key,\n    /// be it a unique or primary one.\n    pub const ER_DUP_ENTRY: u16 = 1062;\n    /// Similar to `ER_DUP_ENTRY`, but only present in NDB clusters.\n    ///\n    /// See: <https://github.com/mysql/mysql-server/blob/fbdaa4def30d269bc4de5b85de61de34b11c0afc/mysql-test/suite/stress/include/ddl7.inc#L68>.\n    pub const ER_DUP_UNIQUE: u16 = 1169;\n    /// Similar to `ER_DUP_ENTRY`, but with a formatted string message.\n    ///\n    /// See: <https://bugs.mysql.com/bug.php?id=46976>.\n    pub const ER_DUP_ENTRY_WITH_KEY_NAME: u16 = 1586;\n    /// Caused when a DDL operation to add a unique index fails,\n    /// because duplicate items were created by concurrent DML operations.\n    /// When this happens, the key is unknown, so the server can't use `ER_DUP_KEY`.\n    ///\n    /// For example: an `INSERT` operation creates duplicate `name` fields when `ALTER`ing a table and making `name` unique.\n    pub const ER_DUP_UNKNOWN_IN_INDEX: u16 = 1859;\n\n    /// Caused when inserting an entry with a column with a value that does not reference a foreign row.\n    pub const ER_NO_REFERENCED_ROW: u16 = 1216;\n    /// Caused when deleting a row that is referenced in other tables.\n    pub const ER_ROW_IS_REFERENCED: u16 = 1217;\n    /// Caused when deleting a row that is referenced in other tables.\n    /// This differs from `ER_ROW_IS_REFERENCED` in that the error message contains the affected constraint.\n    pub const ER_ROW_IS_REFERENCED_2: u16 = 1451;\n    /// Caused when inserting an entry with a column with a value that does not reference a foreign row.\n    /// This differs from `ER_NO_REFERENCED_ROW` in that the error message contains the affected constraint.\n    pub const ER_NO_REFERENCED_ROW_2: u16 = 1452;\n    /// Caused when creating a FK with `ON DELETE SET NULL` or `ON UPDATE SET NULL` to a column that is `NOT NULL`, or vice-versa.\n    pub const ER_FK_COLUMN_NOT_NULL: u16 = 1830;\n    /// Removed in 5.7.3.\n    pub const ER_FK_CANNOT_DELETE_PARENT: u16 = 1834;\n\n    /// Caused when inserting a NULL value to a column marked as NOT NULL.\n    pub const ER_BAD_NULL_ERROR: u16 = 1048;\n    /// Caused when inserting a DEFAULT value to a column marked as NOT NULL, which also doesn't have a default value set.\n    pub const ER_NO_DEFAULT_FOR_FIELD: u16 = 1364;\n\n    /// Caused when a check constraint is violated.\n    ///\n    /// Only available after 8.0.16.\n    pub const ER_CHECK_CONSTRAINT_VIOLATED: u16 = 3819;\n\n    pub(crate) mod mariadb {\n        /// Error code emitted by MariaDB for constraint errors: <https://mariadb.com/kb/en/e4025/>\n        ///\n        /// MySQL emits this code for a completely different error:\n        /// <https://dev.mysql.com/doc/mysql-errors/8.4/en/server-error-reference.html#error_er_innodb_autoextend_size_out_of_range>\n        ///\n        /// You also check that SQLSTATE is `23000`.\n        pub const ER_CONSTRAINT_FAILED: u16 = 4025;\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/io/buf.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::BufExt;\n\npub trait MySqlBufExt: Buf {\n    // Read a length-encoded integer.\n    // NOTE: 0xfb or NULL is only returned for binary value encoding to indicate NULL.\n    // NOTE: 0xff is only returned during a result set to indicate ERR.\n    // <https://dev.mysql.com/doc/internals/en/integer.html#packet-Protocol::LengthEncodedInteger>\n    fn get_uint_lenenc(&mut self) -> Result<u64, Error>;\n\n    // Read a length-encoded string.\n    #[allow(dead_code)]\n    fn get_str_lenenc(&mut self) -> Result<String, Error>;\n\n    // Read a length-encoded byte sequence.\n    fn get_bytes_lenenc(&mut self) -> Result<Bytes, Error>;\n}\n\nimpl MySqlBufExt for Bytes {\n    fn get_uint_lenenc(&mut self) -> Result<u64, Error> {\n        if self.remaining() < 1 {\n            return Err(err_protocol!(\"lenenc int: no bytes remaining\"));\n        }\n\n        match self.get_u8() {\n            0xfc => {\n                if self.remaining() < 2 {\n                    return Err(err_protocol!(\n                        \"lenenc int: need 2 more bytes, have {}\",\n                        self.remaining()\n                    ));\n                }\n                Ok(u64::from(self.get_u16_le()))\n            }\n            0xfd => {\n                if self.remaining() < 3 {\n                    return Err(err_protocol!(\n                        \"lenenc int: need 3 more bytes, have {}\",\n                        self.remaining()\n                    ));\n                }\n                Ok(self.get_uint_le(3))\n            }\n            0xfe => {\n                if self.remaining() < 8 {\n                    return Err(err_protocol!(\n                        \"lenenc int: need 8 more bytes, have {}\",\n                        self.remaining()\n                    ));\n                }\n                Ok(self.get_u64_le())\n            }\n\n            v => Ok(u64::from(v)),\n        }\n    }\n\n    fn get_str_lenenc(&mut self) -> Result<String, Error> {\n        let size = self.get_uint_lenenc()?;\n        let size = usize::try_from(size)\n            .map_err(|_| err_protocol!(\"string length overflows usize: {size}\"))?;\n\n        self.get_str(size)\n    }\n\n    fn get_bytes_lenenc(&mut self) -> Result<Bytes, Error> {\n        let size = self.get_uint_lenenc()?;\n        let size = usize::try_from(size)\n            .map_err(|_| err_protocol!(\"string length overflows usize: {size}\"))?;\n\n        Ok(self.split_to(size))\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/io/buf_mut.rs",
    "content": "use bytes::BufMut;\n\npub trait MySqlBufMutExt: BufMut {\n    fn put_uint_lenenc(&mut self, v: u64);\n\n    fn put_str_lenenc(&mut self, v: &str);\n\n    fn put_bytes_lenenc(&mut self, v: &[u8]);\n}\n\nimpl MySqlBufMutExt for Vec<u8> {\n    fn put_uint_lenenc(&mut self, v: u64) {\n        // https://dev.mysql.com/doc/internals/en/integer.html\n        // https://mariadb.com/kb/en/library/protocol-data-types/#length-encoded-integers\n\n        let encoded_le = v.to_le_bytes();\n\n        match v {\n            0..=250 => self.push(encoded_le[0]),\n            251..=0xFF_FF => {\n                self.push(0xfc);\n                self.extend_from_slice(&encoded_le[..2]);\n            }\n            0x1_00_00..=0xFF_FF_FF => {\n                self.push(0xfd);\n                self.extend_from_slice(&encoded_le[..3]);\n            }\n            _ => {\n                self.push(0xfe);\n                self.extend_from_slice(&encoded_le);\n            }\n        }\n    }\n\n    fn put_str_lenenc(&mut self, v: &str) {\n        self.put_bytes_lenenc(v.as_bytes());\n    }\n\n    fn put_bytes_lenenc(&mut self, v: &[u8]) {\n        self.put_uint_lenenc(v.len() as u64);\n        self.extend(v);\n    }\n}\n\n#[test]\nfn test_encodes_int_lenenc_u8() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFA_u64);\n\n    assert_eq!(&buf[..], b\"\\xFA\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_u16() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(u16::MAX as u64);\n\n    assert_eq!(&buf[..], b\"\\xFC\\xFF\\xFF\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_u24() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFF_FF_FF_u64);\n\n    assert_eq!(&buf[..], b\"\\xFD\\xFF\\xFF\\xFF\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_u64() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(u64::MAX);\n\n    assert_eq!(&buf[..], b\"\\xFE\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\\xFF\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_fb() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFB_u64);\n\n    assert_eq!(&buf[..], b\"\\xFC\\xFB\\x00\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_fc() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFC_u64);\n\n    assert_eq!(&buf[..], b\"\\xFC\\xFC\\x00\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_fd() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFD_u64);\n\n    assert_eq!(&buf[..], b\"\\xFC\\xFD\\x00\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_fe() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFE_u64);\n\n    assert_eq!(&buf[..], b\"\\xFC\\xFE\\x00\");\n}\n\n#[test]\nfn test_encodes_int_lenenc_ff() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_uint_lenenc(0xFF_u64);\n\n    assert_eq!(&buf[..], b\"\\xFC\\xFF\\x00\");\n}\n\n#[test]\nfn test_encodes_string_lenenc() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_str_lenenc(\"random_string\");\n\n    assert_eq!(&buf[..], b\"\\x0Drandom_string\");\n}\n\n#[test]\nfn test_encodes_byte_lenenc() {\n    let mut buf = Vec::with_capacity(1024);\n    buf.put_bytes_lenenc(b\"random_string\");\n\n    assert_eq!(&buf[..], b\"\\x0Drandom_string\");\n}\n"
  },
  {
    "path": "sqlx-mysql/src/io/mod.rs",
    "content": "mod buf;\nmod buf_mut;\n\npub use buf::MySqlBufExt;\npub use buf_mut::MySqlBufMutExt;\n\npub(crate) use sqlx_core::io::*;\n"
  },
  {
    "path": "sqlx-mysql/src/lib.rs",
    "content": "//! **MySQL** database driver.\n#![deny(clippy::cast_possible_truncation)]\n#![deny(clippy::cast_possible_wrap)]\n#![deny(clippy::cast_sign_loss)]\n\n#[macro_use]\nextern crate sqlx_core;\n\nuse crate::executor::Executor;\n\npub(crate) use sqlx_core::driver_prelude::*;\n\n#[cfg(feature = \"any\")]\npub mod any;\n\nmod arguments;\nmod collation;\nmod column;\nmod connection;\nmod database;\nmod error;\nmod io;\nmod options;\nmod protocol;\nmod query_result;\nmod row;\nmod statement;\nmod transaction;\nmod type_checking;\nmod type_info;\npub mod types;\nmod value;\n\n#[cfg(feature = \"migrate\")]\nmod migrate;\n\n#[cfg(feature = \"migrate\")]\nmod testing;\n\npub use arguments::MySqlArguments;\npub use column::MySqlColumn;\npub use connection::MySqlConnection;\npub use database::MySql;\npub use error::MySqlDatabaseError;\npub use options::{MySqlConnectOptions, MySqlSslMode};\npub use query_result::MySqlQueryResult;\npub use row::MySqlRow;\npub use statement::MySqlStatement;\npub use transaction::MySqlTransactionManager;\npub use type_info::MySqlTypeInfo;\npub use value::{MySqlValue, MySqlValueFormat, MySqlValueRef};\n\n/// An alias for [`Pool`][crate::pool::Pool], specialized for MySQL.\npub type MySqlPool = crate::pool::Pool<MySql>;\n\n/// An alias for [`PoolOptions`][crate::pool::PoolOptions], specialized for MySQL.\npub type MySqlPoolOptions = crate::pool::PoolOptions<MySql>;\n\n/// An alias for [`Executor<'_, Database = MySql>`][Executor].\npub trait MySqlExecutor<'c>: Executor<'c, Database = MySql> {}\nimpl<'c, T: Executor<'c, Database = MySql>> MySqlExecutor<'c> for T {}\n\n/// An alias for [`Transaction`][crate::transaction::Transaction], specialized for MySQL.\npub type MySqlTransaction<'c> = crate::transaction::Transaction<'c, MySql>;\n\n// NOTE: required due to the lack of lazy normalization\nimpl_into_arguments_for_arguments!(MySqlArguments);\nimpl_acquire!(MySql, MySqlConnection);\nimpl_column_index_for_row!(MySqlRow);\nimpl_column_index_for_statement!(MySqlStatement);\n\n// required because some databases have a different handling of NULL\nimpl_encode_for_option!(MySql);\n"
  },
  {
    "path": "sqlx-mysql/src/migrate.rs",
    "content": "use std::str::FromStr;\nuse std::time::Duration;\nuse std::time::Instant;\n\nuse futures_core::future::BoxFuture;\npub(crate) use sqlx_core::migrate::*;\nuse sqlx_core::sql_str::AssertSqlSafe;\n\nuse crate::connection::{ConnectOptions, Connection};\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::query::query;\nuse crate::query_as::query_as;\nuse crate::query_scalar::query_scalar;\nuse crate::{MySql, MySqlConnectOptions, MySqlConnection};\n\nfn parse_for_maintenance(url: &str) -> Result<(MySqlConnectOptions, String), Error> {\n    let mut options = MySqlConnectOptions::from_str(url)?;\n\n    let database = if let Some(database) = &options.database {\n        database.to_owned()\n    } else {\n        return Err(Error::Configuration(\n            \"DATABASE_URL does not specify a database\".into(),\n        ));\n    };\n\n    // switch us to <no> database for create/drop commands\n    options.database = None;\n\n    Ok((options, database))\n}\n\nimpl MigrateDatabase for MySql {\n    async fn create_database(url: &str) -> Result<(), Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let _ = conn\n            .execute(AssertSqlSafe(format!(\"CREATE DATABASE `{database}`\")))\n            .await?;\n\n        Ok(())\n    }\n\n    async fn database_exists(url: &str) -> Result<bool, Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let exists: bool = query_scalar(\n            \"select exists(SELECT 1 from INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = ?)\",\n        )\n        .bind(database)\n        .fetch_one(&mut conn)\n        .await?;\n\n        Ok(exists)\n    }\n\n    async fn drop_database(url: &str) -> Result<(), Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let _ = conn\n            .execute(AssertSqlSafe(format!(\n                \"DROP DATABASE IF EXISTS `{database}`\"\n            )))\n            .await?;\n\n        Ok(())\n    }\n}\n\nimpl Migrate for MySqlConnection {\n    fn create_schema_if_not_exists<'e>(\n        &'e mut self,\n        schema_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            self.execute(AssertSqlSafe(format!(\n                r#\"CREATE SCHEMA IF NOT EXISTS {schema_name};\"#\n            )))\n            .await?;\n\n            Ok(())\n        })\n    }\n\n    fn ensure_migrations_table<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async move {\n            // language=MySQL\n            self.execute(AssertSqlSafe(format!(\n                r#\"\nCREATE TABLE IF NOT EXISTS {table_name} (\n    version BIGINT PRIMARY KEY,\n    description TEXT NOT NULL,\n    installed_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    success BOOLEAN NOT NULL,\n    checksum BLOB NOT NULL,\n    execution_time BIGINT NOT NULL\n);\n                \"#\n            )))\n            .await?;\n\n            Ok(())\n        })\n    }\n\n    fn dirty_version<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Option<i64>, MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            let row: Option<(i64,)> = query_as(AssertSqlSafe(format!(\n                \"SELECT version FROM {table_name} WHERE success = false ORDER BY version LIMIT 1\"\n            )))\n            .fetch_optional(self)\n            .await?;\n\n            Ok(row.map(|r| r.0))\n        })\n    }\n\n    fn list_applied_migrations<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            let rows: Vec<(i64, Vec<u8>)> = query_as(AssertSqlSafe(format!(\n                \"SELECT version, checksum FROM {table_name} ORDER BY version\"\n            )))\n            .fetch_all(self)\n            .await?;\n\n            let migrations = rows\n                .into_iter()\n                .map(|(version, checksum)| AppliedMigration {\n                    version,\n                    checksum: checksum.into(),\n                })\n                .collect();\n\n            Ok(migrations)\n        })\n    }\n\n    fn lock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async move {\n            let database_name = current_database(self).await?;\n            let lock_id = generate_lock_id(&database_name);\n\n            // create an application lock over the database\n            // this function will not return until the lock is acquired\n\n            // https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS\n            // https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS-TABLE\n\n            // language=MySQL\n            let _ = query(\"SELECT GET_LOCK(?, -1)\")\n                .bind(lock_id)\n                .execute(self)\n                .await?;\n\n            Ok(())\n        })\n    }\n\n    fn unlock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async move {\n            let database_name = current_database(self).await?;\n            let lock_id = generate_lock_id(&database_name);\n\n            // language=MySQL\n            let _ = query(\"SELECT RELEASE_LOCK(?)\")\n                .bind(lock_id)\n                .execute(self)\n                .await?;\n\n            Ok(())\n        })\n    }\n\n    fn apply<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async move {\n            // Use a single transaction for the actual migration script and the essential bookkeeping so we never\n            // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.\n            // The `execution_time` however can only be measured for the whole transaction. This value _only_ exists for\n            // data lineage and debugging reasons, so it is not super important if it is lost. So we initialize it to -1\n            // and update it once the actual transaction completed.\n            let mut tx = self.begin().await?;\n            let start = Instant::now();\n\n            // For MySQL we cannot really isolate migrations due to implicit commits caused by table modification, see\n            // https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html\n            //\n            // To somewhat try to detect this, we first insert the migration into the migration table with\n            // `success=FALSE` and later modify the flag.\n            //\n            // language=MySQL\n            let _ = query(AssertSqlSafe(format!(\n                r#\"\n    INSERT INTO {table_name} ( version, description, success, checksum, execution_time )\n    VALUES ( ?, ?, FALSE, ?, -1 )\n                \"#\n            )))\n            .bind(migration.version)\n            .bind(&*migration.description)\n            .bind(&*migration.checksum)\n            .execute(&mut *tx)\n            .await?;\n\n            let _ = tx\n                .execute(migration.sql.clone())\n                .await\n                .map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;\n\n            // language=MySQL\n            let _ = query(AssertSqlSafe(format!(\n                r#\"\n    UPDATE {table_name}\n    SET success = TRUE\n    WHERE version = ?\n                \"#\n            )))\n            .bind(migration.version)\n            .execute(&mut *tx)\n            .await?;\n\n            tx.commit().await?;\n\n            // Update `elapsed_time`.\n            // NOTE: The process may disconnect/die at this point, so the elapsed time value might be lost. We accept\n            //       this small risk since this value is not super important.\n\n            let elapsed = start.elapsed();\n\n            #[allow(clippy::cast_possible_truncation)]\n            let _ = query(AssertSqlSafe(format!(\n                r#\"\n    UPDATE {table_name}\n    SET execution_time = ?\n    WHERE version = ?\n                \"#\n            )))\n            .bind(elapsed.as_nanos() as i64)\n            .bind(migration.version)\n            .execute(self)\n            .await?;\n\n            Ok(elapsed)\n        })\n    }\n\n    fn revert<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async move {\n            // Use a single transaction for the actual migration script and the essential bookkeeping so we never\n            // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.\n            let mut tx = self.begin().await?;\n            let start = Instant::now();\n\n            // For MySQL we cannot really isolate migrations due to implicit commits caused by table modification, see\n            // https://dev.mysql.com/doc/refman/8.0/en/implicit-commit.html\n            //\n            // To somewhat try to detect this, we first insert the migration into the migration table with\n            // `success=FALSE` and later remove the migration altogether.\n            //\n            // language=MySQL\n            let _ = query(AssertSqlSafe(format!(\n                r#\"\n    UPDATE {table_name}\n    SET success = FALSE\n    WHERE version = ?\n                \"#\n            )))\n            .bind(migration.version)\n            .execute(&mut *tx)\n            .await?;\n\n            tx.execute(migration.sql.clone()).await?;\n\n            // language=SQL\n            let _ = query(AssertSqlSafe(format!(\n                r#\"DELETE FROM {table_name} WHERE version = ?\"#\n            )))\n            .bind(migration.version)\n            .execute(&mut *tx)\n            .await?;\n\n            tx.commit().await?;\n\n            let elapsed = start.elapsed();\n\n            Ok(elapsed)\n        })\n    }\n}\n\nasync fn current_database(conn: &mut MySqlConnection) -> Result<String, MigrateError> {\n    // language=MySQL\n    Ok(query_scalar(\"SELECT DATABASE()\").fetch_one(conn).await?)\n}\n\n// inspired from rails: https://github.com/rails/rails/blob/6e49cc77ab3d16c06e12f93158eaf3e507d4120e/activerecord/lib/active_record/migration.rb#L1308\nfn generate_lock_id(database_name: &str) -> String {\n    const CRC_IEEE: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);\n    // 0x3d32ad9e chosen by fair dice roll\n    format!(\n        \"{:x}\",\n        0x3d32ad9e * (CRC_IEEE.checksum(database_name.as_bytes()) as i64)\n    )\n}\n"
  },
  {
    "path": "sqlx-mysql/src/options/connect.rs",
    "content": "use crate::connection::ConnectOptions;\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::{MySqlConnectOptions, MySqlConnection};\nuse log::LevelFilter;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse sqlx_core::Url;\nuse std::time::Duration;\n\nimpl ConnectOptions for MySqlConnectOptions {\n    type Connection = MySqlConnection;\n\n    fn from_url(url: &Url) -> Result<Self, Error> {\n        Self::parse_from_url(url)\n    }\n\n    fn to_url_lossy(&self) -> Url {\n        self.build_url()\n    }\n\n    async fn connect(&self) -> Result<Self::Connection, Error>\n    where\n        Self::Connection: Sized,\n    {\n        let mut conn = MySqlConnection::establish(self).await?;\n\n        // After the connection is established, we initialize by configuring a few\n        // connection parameters\n\n        // https://mariadb.com/kb/en/sql-mode/\n\n        // PIPES_AS_CONCAT - Allows using the pipe character (ASCII 124) as string concatenation operator.\n        //                   This means that \"A\" || \"B\" can be used in place of CONCAT(\"A\", \"B\").\n\n        // NO_ENGINE_SUBSTITUTION - If not set, if the available storage engine specified by a CREATE TABLE is\n        //                          not available, a warning is given and the default storage\n        //                          engine is used instead.\n\n        // NO_ZERO_DATE - Don't allow '0000-00-00'. This is invalid in Rust.\n\n        // NO_ZERO_IN_DATE - Don't allow 'YYYY-00-00'. This is invalid in Rust.\n\n        // --\n\n        // Setting the time zone allows us to assume that the output\n        // from a TIMESTAMP field is UTC\n\n        // --\n\n        // https://mathiasbynens.be/notes/mysql-utf8mb4\n\n        let mut sql_mode = Vec::new();\n        if self.pipes_as_concat {\n            sql_mode.push(r#\"PIPES_AS_CONCAT\"#);\n        }\n        if self.no_engine_substitution {\n            sql_mode.push(r#\"NO_ENGINE_SUBSTITUTION\"#);\n        }\n\n        let mut options = Vec::new();\n        if !sql_mode.is_empty() {\n            options.push(format!(\n                r#\"sql_mode=(SELECT CONCAT(@@sql_mode, ',{}'))\"#,\n                sql_mode.join(\",\")\n            ));\n        }\n\n        if let Some(timezone) = &self.timezone {\n            options.push(format!(r#\"time_zone='{}'\"#, timezone));\n        }\n\n        if self.set_names {\n            // As it turns out, we don't _have_ to set a collation if we don't want to.\n            // We can let the server choose the default collation for the charset.\n            let set_names = if let Some(collation) = &self.collation {\n                format!(r#\"NAMES {} COLLATE {collation}\"#, self.charset,)\n            } else {\n                // Leaves the default collation up to the server,\n                // but ensures statements and results are encoded using the proper charset.\n                format!(\"NAMES {}\", self.charset)\n            };\n\n            options.push(set_names);\n        }\n\n        if !options.is_empty() {\n            conn.execute(AssertSqlSafe(format!(r#\"SET {};\"#, options.join(\",\"))))\n                .await?;\n        }\n\n        Ok(conn)\n    }\n\n    fn log_statements(mut self, level: LevelFilter) -> Self {\n        self.log_settings.log_statements(level);\n        self\n    }\n\n    fn log_slow_statements(mut self, level: LevelFilter, duration: Duration) -> Self {\n        self.log_settings.log_slow_statements(level, duration);\n        self\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/options/mod.rs",
    "content": "use std::path::{Path, PathBuf};\n\nmod connect;\nmod parse;\nmod ssl_mode;\n\nuse crate::{connection::LogSettings, net::tls::CertificateInput};\npub use ssl_mode::MySqlSslMode;\n\n/// Options and flags which can be used to configure a MySQL connection.\n///\n/// A value of `MySqlConnectOptions` can be parsed from a connection URL,\n/// as described by [MySQL](https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-jdbc-url-format.html).\n///\n/// The generic format of the connection URL:\n///\n/// ```text\n/// mysql://[host][/database][?properties]\n/// ```\n///\n/// This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string\n/// containing a connection URL and then further adjust options if necessary (see example below).\n///\n/// ## Properties\n///\n/// |Parameter|Default|Description|\n/// |---------|-------|-----------|\n/// | `ssl-mode` | `PREFERRED` | Determines whether or with what priority a secure SSL TCP/IP connection will be negotiated. See [`MySqlSslMode`]. |\n/// | `ssl-ca` | `None` | Sets the name of a file containing a list of trusted SSL Certificate Authorities. |\n/// | `statement-cache-capacity` | `100` | The maximum number of prepared statements stored in the cache. Set to `0` to disable. |\n/// | `socket` | `None` | Path to the unix domain socket, which will be used instead of TCP if set. |\n///\n/// # Example\n///\n/// ```rust,no_run\n/// # async fn example() -> sqlx::Result<()> {\n/// use sqlx::{Connection, ConnectOptions};\n/// use sqlx::mysql::{MySqlConnectOptions, MySqlConnection, MySqlPool, MySqlSslMode};\n///\n/// // URL connection string\n/// let conn = MySqlConnection::connect(\"mysql://root:password@localhost/db\").await?;\n///\n/// // Manually-constructed options\n/// let conn = MySqlConnectOptions::new()\n///     .host(\"localhost\")\n///     .username(\"root\")\n///     .password(\"password\")\n///     .database(\"db\")\n///     .connect().await?;\n///\n/// // Modifying options parsed from a string\n/// let mut opts: MySqlConnectOptions = \"mysql://root:password@localhost/db\".parse()?;\n///\n/// // Change the log verbosity level for queries.\n/// // Information about SQL queries is logged at `DEBUG` level by default.\n/// opts = opts.log_statements(log::LevelFilter::Trace);\n///\n/// let pool = MySqlPool::connect_with(opts).await?;\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Debug, Clone)]\npub struct MySqlConnectOptions {\n    pub(crate) host: String,\n    pub(crate) port: u16,\n    pub(crate) socket: Option<PathBuf>,\n    pub(crate) username: String,\n    pub(crate) password: Option<String>,\n    pub(crate) database: Option<String>,\n    pub(crate) ssl_mode: MySqlSslMode,\n    pub(crate) ssl_ca: Option<CertificateInput>,\n    pub(crate) ssl_client_cert: Option<CertificateInput>,\n    pub(crate) ssl_client_key: Option<CertificateInput>,\n    pub(crate) statement_cache_capacity: usize,\n    pub(crate) charset: String,\n    pub(crate) collation: Option<String>,\n    pub(crate) log_settings: LogSettings,\n    pub(crate) pipes_as_concat: bool,\n    pub(crate) enable_cleartext_plugin: bool,\n    pub(crate) no_engine_substitution: bool,\n    pub(crate) timezone: Option<String>,\n    pub(crate) set_names: bool,\n}\n\nimpl Default for MySqlConnectOptions {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl MySqlConnectOptions {\n    /// Creates a new, default set of options ready for configuration\n    pub fn new() -> Self {\n        Self {\n            port: 3306,\n            host: String::from(\"localhost\"),\n            socket: None,\n            username: String::from(\"root\"),\n            password: None,\n            database: None,\n            charset: String::from(\"utf8mb4\"),\n            collation: None,\n            ssl_mode: MySqlSslMode::Preferred,\n            ssl_ca: None,\n            ssl_client_cert: None,\n            ssl_client_key: None,\n            statement_cache_capacity: 100,\n            log_settings: Default::default(),\n            pipes_as_concat: true,\n            enable_cleartext_plugin: false,\n            no_engine_substitution: true,\n            timezone: Some(String::from(\"+00:00\")),\n            set_names: true,\n        }\n    }\n\n    /// Sets the name of the host to connect to.\n    ///\n    /// The default behavior when the host is not specified,\n    /// is to connect to localhost.\n    pub fn host(mut self, host: &str) -> Self {\n        host.clone_into(&mut self.host);\n        self\n    }\n\n    /// Sets the port to connect to at the server host.\n    ///\n    /// The default port for MySQL is `3306`.\n    pub fn port(mut self, port: u16) -> Self {\n        self.port = port;\n        self\n    }\n\n    /// Pass a path to a Unix socket. This changes the connection stream from\n    /// TCP to UDS.\n    ///\n    /// By default set to `None`.\n    pub fn socket(mut self, path: impl AsRef<Path>) -> Self {\n        self.socket = Some(path.as_ref().to_path_buf());\n        self\n    }\n\n    /// Sets the username to connect as.\n    pub fn username(mut self, username: &str) -> Self {\n        username.clone_into(&mut self.username);\n        self\n    }\n\n    /// Sets the password to connect with.\n    pub fn password(mut self, password: &str) -> Self {\n        self.password = Some(password.to_owned());\n        self\n    }\n\n    /// Sets the database name.\n    pub fn database(mut self, database: &str) -> Self {\n        self.database = Some(database.to_owned());\n        self\n    }\n\n    /// Sets whether or with what priority a secure SSL TCP/IP connection will be negotiated\n    /// with the server.\n    ///\n    /// By default, the SSL mode is [`Preferred`](MySqlSslMode::Preferred), and the client will\n    /// first attempt an SSL connection but fallback to a non-SSL connection on failure.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::Required);\n    /// ```\n    pub fn ssl_mode(mut self, mode: MySqlSslMode) -> Self {\n        self.ssl_mode = mode;\n        self\n    }\n\n    /// Sets the name of a file containing a list of trusted SSL Certificate Authorities.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::VerifyCa)\n    ///     .ssl_ca(\"path/to/ca.crt\");\n    /// ```\n    pub fn ssl_ca(mut self, file_name: impl AsRef<Path>) -> Self {\n        self.ssl_ca = Some(CertificateInput::File(file_name.as_ref().to_owned()));\n        self\n    }\n\n    /// Sets PEM encoded list of trusted SSL Certificate Authorities.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::VerifyCa)\n    ///     .ssl_ca_from_pem(vec![]);\n    /// ```\n    pub fn ssl_ca_from_pem(mut self, pem_certificate: Vec<u8>) -> Self {\n        self.ssl_ca = Some(CertificateInput::Inline(pem_certificate));\n        self\n    }\n\n    /// Sets the name of a file containing SSL client certificate.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::VerifyCa)\n    ///     .ssl_client_cert(\"path/to/client.crt\");\n    /// ```\n    pub fn ssl_client_cert(mut self, cert: impl AsRef<Path>) -> Self {\n        self.ssl_client_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf()));\n        self\n    }\n\n    /// Sets the SSL client certificate as a PEM-encoded byte slice.\n    ///\n    /// This should be an ASCII-encoded blob that starts with `-----BEGIN CERTIFICATE-----`.\n    ///\n    /// # Example\n    /// Note: embedding SSL certificates and keys in the binary is not advised.\n    /// This is for illustration purposes only.\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    ///\n    /// const CERT: &[u8] = b\"\\\n    /// -----BEGIN CERTIFICATE-----\n    /// <Certificate data here.>\n    /// -----END CERTIFICATE-----\";\n    ///\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::VerifyCa)\n    ///     .ssl_client_cert_from_pem(CERT);\n    /// ```\n    pub fn ssl_client_cert_from_pem(mut self, cert: impl AsRef<[u8]>) -> Self {\n        self.ssl_client_cert = Some(CertificateInput::Inline(cert.as_ref().to_vec()));\n        self\n    }\n\n    /// Sets the name of a file containing SSL client key.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::VerifyCa)\n    ///     .ssl_client_key(\"path/to/client.key\");\n    /// ```\n    pub fn ssl_client_key(mut self, key: impl AsRef<Path>) -> Self {\n        self.ssl_client_key = Some(CertificateInput::File(key.as_ref().to_path_buf()));\n        self\n    }\n\n    /// Sets the SSL client key as a PEM-encoded byte slice.\n    ///\n    /// This should be an ASCII-encoded blob that starts with `-----BEGIN PRIVATE KEY-----`.\n    ///\n    /// # Example\n    /// Note: embedding SSL certificates and keys in the binary is not advised.\n    /// This is for illustration purposes only.\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlSslMode, MySqlConnectOptions};\n    ///\n    /// const KEY: &[u8] = b\"\\\n    /// -----BEGIN PRIVATE KEY-----\n    /// <Private key data here.>\n    /// -----END PRIVATE KEY-----\";\n    ///\n    /// let options = MySqlConnectOptions::new()\n    ///     .ssl_mode(MySqlSslMode::VerifyCa)\n    ///     .ssl_client_key_from_pem(KEY);\n    /// ```\n    pub fn ssl_client_key_from_pem(mut self, key: impl AsRef<[u8]>) -> Self {\n        self.ssl_client_key = Some(CertificateInput::Inline(key.as_ref().to_vec()));\n        self\n    }\n\n    /// Sets the capacity of the connection's statement cache in a number of stored\n    /// distinct statements. Caching is handled using LRU, meaning when the\n    /// amount of queries hits the defined limit, the oldest statement will get\n    /// dropped.\n    ///\n    /// The default cache capacity is 100 statements.\n    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {\n        self.statement_cache_capacity = capacity;\n        self\n    }\n\n    /// Sets the character set for the connection.\n    ///\n    /// The default character set is `utf8mb4`. This is supported from MySQL 5.5.3.\n    /// If you need to connect to an older version, we recommend you to change this to `utf8`.\n    ///\n    /// Implies [`.set_names(true)`][Self::set_names()].\n    pub fn charset(mut self, charset: &str) -> Self {\n        self.set_names = true;\n        charset.clone_into(&mut self.charset);\n        self\n    }\n\n    /// Sets the collation for the connection.\n    ///\n    /// The default collation is derived on the server from the `charset`, if set.\n    /// Normally, you should only have to set the `charset`.\n    ///\n    /// If setting this, it is recommended to also set [`charset`][Self::charset()].\n    ///\n    /// Implies [`.set_names(true)`][Self::set_names()].\n    pub fn collation(mut self, collation: &str) -> Self {\n        self.set_names = true;\n        self.collation = Some(collation.to_owned());\n        self\n    }\n\n    /// Sets the flag that enables or disables the `PIPES_AS_CONCAT` connection setting\n    ///\n    /// The default value is set to true, but some MySql databases such as PlanetScale\n    /// error out with this connection setting so it needs to be set false in such\n    /// cases.\n    pub fn pipes_as_concat(mut self, flag_val: bool) -> Self {\n        self.pipes_as_concat = flag_val;\n        self\n    }\n\n    /// Enables mysql_clear_password plugin support.\n    ///\n    /// Security Note:\n    /// Sending passwords as cleartext may be a security problem in some\n    /// configurations. Without additional defensive configuration like\n    /// ssl-mode=VERIFY_IDENTITY, an attacker can compromise a router\n    /// and trick the application into divulging its credentials.\n    ///\n    /// It is strongly recommended to set `.ssl_mode` to `Required`,\n    /// `VerifyCa`, or `VerifyIdentity` when enabling cleartext plugin.\n    pub fn enable_cleartext_plugin(mut self, flag_val: bool) -> Self {\n        self.enable_cleartext_plugin = flag_val;\n        self\n    }\n\n    #[deprecated = \"renamed to .no_engine_substitution()\"]\n    pub fn no_engine_subsitution(self, flag_val: bool) -> Self {\n        self.no_engine_substitution(flag_val)\n    }\n\n    /// Flag that enables or disables the `NO_ENGINE_SUBSTITUTION` sql_mode setting after\n    /// connection.\n    ///\n    /// If not set, if the available storage engine specified by a `CREATE TABLE` is not available,\n    /// a warning is given and the default storage engine is used instead.\n    ///\n    /// By default, this is `true` (`NO_ENGINE_SUBSTITUTION` is passed, forbidding engine\n    /// substitution).\n    ///\n    /// <https://mariadb.com/kb/en/sql-mode/>\n    pub fn no_engine_substitution(mut self, flag_val: bool) -> Self {\n        self.no_engine_substitution = flag_val;\n        self\n    }\n\n    /// If `Some`, sets the `time_zone` option to the given string after connecting to the database.\n    ///\n    /// If `None`, no `time_zone` parameter is sent; the server timezone will be used instead.\n    ///\n    /// Defaults to `Some(String::from(\"+00:00\"))` to ensure all timestamps are in UTC.\n    ///\n    /// ### Warning\n    /// Changing this setting from its default will apply an unexpected skew to any\n    /// `time::OffsetDateTime` or `chrono::DateTime<Utc>` value, whether passed as a parameter or\n    /// decoded as a result. `TIMESTAMP` values are not encoded with their UTC offset in the MySQL\n    /// protocol, so encoding and decoding of these types assumes the server timezone is *always*\n    /// UTC.\n    ///\n    /// If you are changing this option, ensure your application only uses\n    /// `time::PrimitiveDateTime` or `chrono::NaiveDateTime` and that it does not assume these\n    /// timestamps can be placed on a real timeline without applying the proper offset.\n    pub fn timezone(mut self, value: impl Into<Option<String>>) -> Self {\n        self.timezone = value.into();\n        self\n    }\n\n    /// If enabled, [`.charset()`] and [`.collation()`] are set with the appropriate command.\n    ///\n    /// If only `.charset()`\n    ///\n    /// This ensures the connection uses the specified character set and collation.\n    ///\n    /// Enabled by default.\n    ///\n    /// ### Warning\n    /// If this is disabled and the default charset is not binary-compatible with UTF-8, query\n    /// strings, column names and string values will likely not decode (or encode) correctly, which\n    /// may result in unexpected errors or garbage outputs at runtime.\n    ///\n    /// For proper functioning, you *must* ensure the server is using a binary-compatible charset,\n    /// such as ASCII or Latin-1 (ISO 8859-1), and that you do not pass any strings containing\n    /// codepoints not supported by said charset.\n    ///\n    /// Instead of disabling this, you may also consider setting [`.charset()`] to a charset that\n    /// is supported by your MySQL or MariaDB server version and compatible with UTF-8.\n    ///\n    /// [`.charset`]: Self::charset()\n    pub fn set_names(mut self, flag_val: bool) -> Self {\n        self.set_names = flag_val;\n        self\n    }\n}\n\nimpl MySqlConnectOptions {\n    /// Get the current host.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new()\n    ///     .host(\"127.0.0.1\");\n    /// assert_eq!(options.get_host(), \"127.0.0.1\");\n    /// ```\n    pub fn get_host(&self) -> &str {\n        &self.host\n    }\n\n    /// Get the server's port.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new()\n    ///     .port(6543);\n    /// assert_eq!(options.get_port(), 6543);\n    /// ```\n    pub fn get_port(&self) -> u16 {\n        self.port\n    }\n\n    /// Get the socket path.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new()\n    ///     .socket(\"/tmp\");\n    /// assert!(options.get_socket().is_some());\n    /// ```\n    pub fn get_socket(&self) -> Option<&PathBuf> {\n        self.socket.as_ref()\n    }\n\n    /// Get the current username.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new()\n    ///     .username(\"foo\");\n    /// assert_eq!(options.get_username(), \"foo\");\n    /// ```\n    pub fn get_username(&self) -> &str {\n        &self.username\n    }\n\n    /// Get the current database name.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new()\n    ///     .database(\"postgres\");\n    /// assert!(options.get_database().is_some());\n    /// ```\n    pub fn get_database(&self) -> Option<&str> {\n        self.database.as_deref()\n    }\n\n    /// Get the SSL mode.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::{MySqlConnectOptions, MySqlSslMode};\n    /// let options = MySqlConnectOptions::new();\n    /// assert!(matches!(options.get_ssl_mode(), MySqlSslMode::Preferred));\n    /// ```\n    pub fn get_ssl_mode(&self) -> MySqlSslMode {\n        self.ssl_mode\n    }\n\n    /// Get the server charset.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new();\n    /// assert_eq!(options.get_charset(), \"utf8mb4\");\n    /// ```\n    pub fn get_charset(&self) -> &str {\n        &self.charset\n    }\n\n    /// Get the server collation.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_mysql::MySqlConnectOptions;\n    /// let options = MySqlConnectOptions::new()\n    ///     .collation(\"collation\");\n    /// assert!(options.get_collation().is_some());\n    /// ```\n    pub fn get_collation(&self) -> Option<&str> {\n        self.collation.as_deref()\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/options/parse.rs",
    "content": "use std::str::FromStr;\n\nuse percent_encoding::{percent_decode_str, utf8_percent_encode, NON_ALPHANUMERIC};\nuse sqlx_core::Url;\n\nuse crate::{error::Error, MySqlSslMode};\n\nuse super::MySqlConnectOptions;\n\nimpl MySqlConnectOptions {\n    pub(crate) fn parse_from_url(url: &Url) -> Result<Self, Error> {\n        let mut options = Self::new();\n\n        if let Some(host) = url.host_str() {\n            options = options.host(host);\n        }\n\n        if let Some(port) = url.port() {\n            options = options.port(port);\n        }\n\n        let username = url.username();\n        if !username.is_empty() {\n            options = options.username(\n                &percent_decode_str(username)\n                    .decode_utf8()\n                    .map_err(Error::config)?,\n            );\n        }\n\n        if let Some(password) = url.password() {\n            options = options.password(\n                &percent_decode_str(password)\n                    .decode_utf8()\n                    .map_err(Error::config)?,\n            );\n        }\n\n        let path = url.path().trim_start_matches('/');\n        if !path.is_empty() {\n            options = options.database(\n                &percent_decode_str(path)\n                    .decode_utf8()\n                    .map_err(Error::config)?,\n            );\n        }\n\n        for (key, value) in url.query_pairs().into_iter() {\n            match &*key {\n                \"sslmode\" | \"ssl-mode\" => {\n                    options = options.ssl_mode(value.parse().map_err(Error::config)?);\n                }\n\n                \"sslca\" | \"ssl-ca\" => {\n                    options = options.ssl_ca(&*value);\n                }\n\n                \"charset\" => {\n                    options = options.charset(&value);\n                }\n\n                \"collation\" => {\n                    options = options.collation(&value);\n                }\n\n                \"sslcert\" | \"ssl-cert\" => options = options.ssl_client_cert(&*value),\n\n                \"sslkey\" | \"ssl-key\" => options = options.ssl_client_key(&*value),\n\n                \"statement-cache-capacity\" => {\n                    options =\n                        options.statement_cache_capacity(value.parse().map_err(Error::config)?);\n                }\n\n                \"socket\" => {\n                    options = options.socket(&*value);\n                }\n\n                \"timezone\" | \"time-zone\" => {\n                    options = options.timezone(Some(value.to_string()));\n                }\n\n                _ => {}\n            }\n        }\n\n        Ok(options)\n    }\n\n    pub(crate) fn build_url(&self) -> Url {\n        let mut url = Url::parse(&format!(\n            \"mysql://{}@{}:{}\",\n            self.username, self.host, self.port\n        ))\n        .expect(\"BUG: generated un-parseable URL\");\n\n        if let Some(password) = &self.password {\n            let password = utf8_percent_encode(password, NON_ALPHANUMERIC).to_string();\n            let _ = url.set_password(Some(&password));\n        }\n\n        if let Some(database) = &self.database {\n            url.set_path(database);\n        }\n\n        let ssl_mode = match self.ssl_mode {\n            MySqlSslMode::Disabled => \"DISABLED\",\n            MySqlSslMode::Preferred => \"PREFERRED\",\n            MySqlSslMode::Required => \"REQUIRED\",\n            MySqlSslMode::VerifyCa => \"VERIFY_CA\",\n            MySqlSslMode::VerifyIdentity => \"VERIFY_IDENTITY\",\n        };\n        url.query_pairs_mut().append_pair(\"ssl-mode\", ssl_mode);\n\n        if let Some(ssl_ca) = &self.ssl_ca {\n            url.query_pairs_mut()\n                .append_pair(\"ssl-ca\", &ssl_ca.to_string());\n        }\n\n        url.query_pairs_mut().append_pair(\"charset\", &self.charset);\n\n        if let Some(collation) = &self.collation {\n            url.query_pairs_mut().append_pair(\"charset\", collation);\n        }\n\n        if let Some(ssl_client_cert) = &self.ssl_client_cert {\n            url.query_pairs_mut()\n                .append_pair(\"ssl-cert\", &ssl_client_cert.to_string());\n        }\n\n        if let Some(ssl_client_key) = &self.ssl_client_key {\n            url.query_pairs_mut()\n                .append_pair(\"ssl-key\", &ssl_client_key.to_string());\n        }\n\n        url.query_pairs_mut().append_pair(\n            \"statement-cache-capacity\",\n            &self.statement_cache_capacity.to_string(),\n        );\n\n        if let Some(socket) = &self.socket {\n            url.query_pairs_mut()\n                .append_pair(\"socket\", &socket.to_string_lossy());\n        }\n\n        url\n    }\n}\n\nimpl FromStr for MySqlConnectOptions {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        let url: Url = s.parse().map_err(Error::config)?;\n        Self::parse_from_url(&url)\n    }\n}\n\n#[test]\nfn it_parses_username_with_at_sign_correctly() {\n    let url = \"mysql://user@hostname:password@hostname:5432/database\";\n    let opts = MySqlConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(\"user@hostname\", &opts.username);\n}\n\n#[test]\nfn it_parses_password_with_non_ascii_chars_correctly() {\n    let url = \"mysql://username:p@ssw0rd@hostname:5432/database\";\n    let opts = MySqlConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(Some(\"p@ssw0rd\".into()), opts.password);\n}\n\n#[test]\nfn it_returns_the_parsed_url() {\n    let url = \"mysql://username:p@ssw0rd@hostname:3306/database\";\n    let opts = MySqlConnectOptions::from_str(url).unwrap();\n\n    let mut expected_url = Url::parse(url).unwrap();\n    // MySqlConnectOptions defaults\n    let query_string = \"ssl-mode=PREFERRED&charset=utf8mb4&statement-cache-capacity=100\";\n    expected_url.set_query(Some(query_string));\n\n    assert_eq!(expected_url, opts.build_url());\n}\n\n#[test]\nfn it_parses_timezone() {\n    let opts: MySqlConnectOptions = \"mysql://user:password@hostname/database?timezone=%2B08:00\"\n        .parse()\n        .unwrap();\n    assert_eq!(opts.timezone.as_deref(), Some(\"+08:00\"));\n\n    let opts: MySqlConnectOptions = \"mysql://user:password@hostname/database?time-zone=%2B08:00\"\n        .parse()\n        .unwrap();\n    assert_eq!(opts.timezone.as_deref(), Some(\"+08:00\"));\n}\n"
  },
  {
    "path": "sqlx-mysql/src/options/ssl_mode.rs",
    "content": "use crate::error::Error;\nuse std::str::FromStr;\n\n/// Options for controlling the desired security state of the connection to the MySQL server.\n///\n/// It is used by the [`ssl_mode`](super::MySqlConnectOptions::ssl_mode) method.\n#[derive(Debug, Clone, Copy, Default)]\npub enum MySqlSslMode {\n    /// Establish an unencrypted connection.\n    Disabled,\n\n    /// Establish an encrypted connection if the server supports encrypted connections, falling\n    /// back to an unencrypted connection if an encrypted connection cannot be established.\n    ///\n    /// This is the default if `ssl_mode` is not specified.\n    #[default]\n    Preferred,\n\n    /// Establish an encrypted connection if the server supports encrypted connections.\n    /// The connection attempt fails if an encrypted connection cannot be established.\n    Required,\n\n    /// Like `Required`, but additionally verify the server Certificate Authority (CA)\n    /// certificate against the configured CA certificates. The connection attempt fails\n    /// if no valid matching CA certificates are found.\n    VerifyCa,\n\n    /// Like `VerifyCa`, but additionally perform host name identity verification by\n    /// checking the host name the client uses for connecting to the server against the\n    /// identity in the certificate that the server sends to the client.\n    VerifyIdentity,\n}\n\nimpl FromStr for MySqlSslMode {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        Ok(match &*s.to_ascii_lowercase() {\n            \"disabled\" => MySqlSslMode::Disabled,\n            \"preferred\" => MySqlSslMode::Preferred,\n            \"required\" => MySqlSslMode::Required,\n            \"verify_ca\" => MySqlSslMode::VerifyCa,\n            \"verify_identity\" => MySqlSslMode::VerifyIdentity,\n\n            _ => {\n                return Err(Error::Configuration(\n                    format!(\"unknown value {s:?} for `ssl_mode`\").into(),\n                ));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/auth.rs",
    "content": "use std::str::FromStr;\n\nuse crate::error::Error;\n\n#[derive(Debug, Copy, Clone)]\n// These have all the same suffix but they match the auth plugin names.\n#[allow(clippy::enum_variant_names)]\npub enum AuthPlugin {\n    MySqlNativePassword,\n    CachingSha2Password,\n    Sha256Password,\n    MySqlClearPassword,\n}\n\nimpl AuthPlugin {\n    pub(crate) fn name(self) -> &'static str {\n        match self {\n            AuthPlugin::MySqlNativePassword => \"mysql_native_password\",\n            AuthPlugin::CachingSha2Password => \"caching_sha2_password\",\n            AuthPlugin::Sha256Password => \"sha256_password\",\n            AuthPlugin::MySqlClearPassword => \"mysql_clear_password\",\n        }\n    }\n}\n\nimpl FromStr for AuthPlugin {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"mysql_native_password\" => Ok(AuthPlugin::MySqlNativePassword),\n            \"caching_sha2_password\" => Ok(AuthPlugin::CachingSha2Password),\n            \"sha256_password\" => Ok(AuthPlugin::Sha256Password),\n            \"mysql_clear_password\" => Ok(AuthPlugin::MySqlClearPassword),\n\n            _ => Err(err_protocol!(\"unknown authentication plugin: {}\", s)),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/capabilities.rs",
    "content": "// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/group__group__cs__capabilities__flags.html\n// https://mariadb.com/kb/en/library/connection/#capabilities\n//\n// MySQL defines the capabilities flags as fitting in an `int<4>` but MariaDB\n// extends this with more bits sent in a separate field.\n// For simplicity, we've chosen to combine these into one type.\nbitflags::bitflags! {\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\n    pub struct Capabilities: u64 {\n        // [MariaDB] MySQL compatibility\n        const MYSQL = 1;\n\n        // [*] Send found rows instead of affected rows in EOF_Packet.\n        const FOUND_ROWS = 2;\n\n        // Get all column flags.\n        const LONG_FLAG = 4;\n\n        // [*] Database (schema) name can be specified on connect in Handshake Response Packet.\n        const CONNECT_WITH_DB = 8;\n\n        // Don't allow database.table.column\n        const NO_SCHEMA = 16;\n\n        // [*] Compression protocol supported\n        const COMPRESS = 32;\n\n        // Special handling of ODBC behavior.\n        const ODBC = 64;\n\n        // Can use LOAD DATA LOCAL\n        const LOCAL_FILES = 128;\n\n        // [*] Ignore spaces before '('\n        const IGNORE_SPACE = 256;\n\n        // [*] New 4.1+ protocol\n        const PROTOCOL_41 = 512;\n\n        // This is an interactive client\n        const INTERACTIVE = 1024;\n\n        // Use SSL encryption for this session\n        const SSL = 2048;\n\n        // Client knows about transactions\n        const TRANSACTIONS = 8192;\n\n        // 4.1+ authentication\n        const SECURE_CONNECTION = 1 << 15;\n\n        // Enable/disable multi-statement support for COM_QUERY *and* COM_STMT_PREPARE\n        const MULTI_STATEMENTS = 1 << 16;\n\n        // Enable/disable multi-results for COM_QUERY\n        const MULTI_RESULTS = 1 << 17;\n\n        // Enable/disable multi-results for COM_STMT_PREPARE\n        const PS_MULTI_RESULTS = 1 << 18;\n\n        // Client supports plugin authentication\n        const PLUGIN_AUTH = 1 << 19;\n\n        // Client supports connection attributes\n        const CONNECT_ATTRS = 1 << 20;\n\n        // Enable authentication response packet to be larger than 255 bytes.\n        const PLUGIN_AUTH_LENENC_DATA = 1 << 21;\n\n        // Don't close the connection for a user account with expired password.\n        const CAN_HANDLE_EXPIRED_PASSWORDS = 1 << 22;\n\n        // Capable of handling server state change information.\n        const SESSION_TRACK = 1 << 23;\n\n        // Client no longer needs EOF_Packet and will use OK_Packet instead.\n        const DEPRECATE_EOF = 1 << 24;\n\n        // Support ZSTD protocol compression\n        const ZSTD_COMPRESSION_ALGORITHM = 1 << 26;\n\n        // Verify server certificate\n        const SSL_VERIFY_SERVER_CERT = 1 << 30;\n\n        // The client can handle optional metadata information in the resultset\n        const OPTIONAL_RESULTSET_METADATA = 1 << 25;\n\n        // Don't reset the options after an unsuccessful connect\n        const REMEMBER_OPTIONS = 1 << 31;\n\n        // Extended capabilities (MariaDB only, as of writing)\n        // Client support progress indicator (since 10.2)\n        const MARIADB_CLIENT_PROGRESS = 1 << 32;\n\n        // Permit COM_MULTI protocol\n        const MARIADB_CLIENT_MULTI = 1 << 33;\n\n        // Permit bulk insert\n        const MARIADB_CLIENT_STMT_BULK_OPERATIONS = 1 << 34;\n\n        // Add extended metadata information\n        const MARIADB_CLIENT_EXTENDED_TYPE_INFO = 1 << 35;\n\n        // Permit skipping metadata\n        const MARIADB_CLIENT_CACHE_METADATA = 1 << 36;\n\n        // when enabled, indicate that Bulk command can use STMT_BULK_FLAG_SEND_UNIT_RESULTS flag\n        // that permit to return a result-set of all affected rows and auto-increment values\n        const MARIADB_CLIENT_BULK_UNIT_RESULTS = 1 << 37;\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/connect/auth_switch.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::ProtocolEncode;\nuse crate::io::{BufExt, ProtocolDecode};\nuse crate::protocol::auth::AuthPlugin;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_connection_phase_packets_protocol_auth_switch_request.html\n\n#[derive(Debug)]\npub struct AuthSwitchRequest {\n    pub plugin: AuthPlugin,\n    pub data: Bytes,\n}\n\nimpl ProtocolDecode<'_, bool> for AuthSwitchRequest {\n    fn decode_with(mut buf: Bytes, enable_cleartext_plugin: bool) -> Result<Self, Error> {\n        let header = buf.get_u8();\n        if header != 0xfe {\n            return Err(err_protocol!(\n                \"expected 0xfe (AUTH_SWITCH) but found 0x{:x}\",\n                header\n            ));\n        }\n\n        let plugin = buf.get_str_nul()?.parse()?;\n\n        if matches!(plugin, AuthPlugin::MySqlClearPassword) && !enable_cleartext_plugin {\n            return Err(err_protocol!(\"mysql_cleartext_plugin disabled\"));\n        }\n\n        if matches!(plugin, AuthPlugin::MySqlClearPassword) && buf.is_empty() {\n            // Contrary to the MySQL protocol, AWS Aurora with IAM sends\n            // no data. That is fine because the mysql_clear_password says to\n            // ignore any data sent.\n            // See: https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase_authentication_methods_clear_text_password.html\n            return Ok(Self {\n                plugin,\n                data: Bytes::new(),\n            });\n        }\n\n        // See: https://github.com/mysql/mysql-server/blob/ea7d2e2d16ac03afdd9cb72a972a95981107bf51/sql/auth/sha2_password.cc#L942\n        if buf.len() != 21 {\n            return Err(err_protocol!(\n                \"expected 21 bytes but found {} bytes\",\n                buf.len()\n            ));\n        }\n        let data = buf.get_bytes(20);\n        buf.advance(1); // NUL-terminator\n\n        Ok(Self { plugin, data })\n    }\n}\n\n#[derive(Debug)]\npub struct AuthSwitchResponse(pub Vec<u8>);\n\nimpl ProtocolEncode<'_, Capabilities> for AuthSwitchResponse {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), Error> {\n        buf.extend_from_slice(&self.0);\n        Ok(())\n    }\n}\n\n#[test]\nfn test_decode_auth_switch_packet_data() {\n    const AUTH_SWITCH_NO_DATA: &[u8] = b\"\\xfecaching_sha2_password\\x00abcdefghijabcdefghij\\x00\";\n\n    let p = AuthSwitchRequest::decode_with(AUTH_SWITCH_NO_DATA.into(), true).unwrap();\n\n    assert!(matches!(p.plugin, AuthPlugin::CachingSha2Password));\n    assert_eq!(p.data, &b\"abcdefghijabcdefghij\"[..]);\n}\n\n#[test]\nfn test_decode_auth_switch_cleartext_disabled() {\n    const AUTH_SWITCH_CLEARTEXT: &[u8] = b\"\\xfemysql_clear_password\\x00abcdefghijabcdefghij\\x00\";\n\n    let e = AuthSwitchRequest::decode_with(AUTH_SWITCH_CLEARTEXT.into(), false).unwrap_err();\n\n    let e_str = e.to_string();\n\n    let expected = \"encountered unexpected or invalid data: mysql_cleartext_plugin disabled\";\n\n    assert!(\n        // Don't want to assert the full string since it contains the module path now.\n        e_str.starts_with(expected),\n        \"expected error string to start with {expected:?}, got {e_str:?}\"\n    );\n}\n\n#[test]\nfn test_decode_auth_switch_packet_no_data() {\n    const AUTH_SWITCH_NO_DATA: &[u8] = b\"\\xfemysql_clear_password\\x00\";\n\n    let p = AuthSwitchRequest::decode_with(AUTH_SWITCH_NO_DATA.into(), true).unwrap();\n\n    assert!(matches!(p.plugin, AuthPlugin::MySqlClearPassword));\n    assert_eq!(p.data, Bytes::new());\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/connect/handshake.rs",
    "content": "use bytes::buf::Chain;\nuse bytes::{Buf, Bytes};\nuse std::cmp;\n\nuse crate::error::Error;\nuse crate::io::{BufExt, ProtocolDecode};\nuse crate::protocol::auth::AuthPlugin;\nuse crate::protocol::response::Status;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake\n// https://mariadb.com/kb/en/connection/#initial-handshake-packet\n\n#[derive(Debug)]\npub(crate) struct Handshake {\n    #[allow(unused)]\n    pub(crate) protocol_version: u8,\n    pub(crate) server_version: String,\n    #[allow(unused)]\n    pub(crate) connection_id: u32,\n    pub(crate) server_capabilities: Capabilities,\n    #[allow(unused)]\n    pub(crate) server_default_collation: u8,\n    #[allow(unused)]\n    pub(crate) status: Status,\n    pub(crate) auth_plugin: Option<AuthPlugin>,\n    pub(crate) auth_plugin_data: Chain<Bytes, Bytes>,\n}\n\nimpl ProtocolDecode<'_> for Handshake {\n    fn decode_with(mut buf: Bytes, _: ()) -> Result<Self, Error> {\n        let protocol_version = buf.get_u8(); // int<1>\n        let server_version = buf.get_str_nul()?; // string<NUL>\n        let connection_id = buf.get_u32_le(); // int<4>\n        let auth_plugin_data_1 = buf.get_bytes(8); // string<8>\n\n        buf.advance(1); // reserved: string<1>\n\n        let capabilities_1 = buf.get_u16_le(); // int<2>\n        let mut capabilities = Capabilities::from_bits_truncate(capabilities_1.into());\n\n        let collation = buf.get_u8(); // int<1>\n        let status = Status::from_bits_truncate(buf.get_u16_le());\n\n        let capabilities_2 = buf.get_u16_le(); // int<2>\n        capabilities |= Capabilities::from_bits_truncate(((capabilities_2 as u32) << 16).into());\n\n        let auth_plugin_data_len = if capabilities.contains(Capabilities::PLUGIN_AUTH) {\n            buf.get_u8()\n        } else {\n            buf.advance(1); // int<1>\n            0\n        };\n\n        buf.advance(6); // reserved: string<6>\n\n        if capabilities.contains(Capabilities::MYSQL) {\n            buf.advance(4); // reserved: string<4>\n        } else {\n            let capabilities_3 = buf.get_u32_le(); // int<4>\n            capabilities |= Capabilities::from_bits_truncate((capabilities_3 as u64) << 32);\n        }\n\n        let auth_plugin_data_2 = if capabilities.contains(Capabilities::SECURE_CONNECTION) {\n            let len = cmp::max(auth_plugin_data_len.saturating_sub(9), 12);\n            let v = buf.get_bytes(len as usize);\n            buf.advance(1); // NUL-terminator\n\n            v\n        } else {\n            Bytes::new()\n        };\n\n        let auth_plugin = if capabilities.contains(Capabilities::PLUGIN_AUTH) {\n            Some(buf.get_str_nul()?.parse()?)\n        } else {\n            None\n        };\n\n        Ok(Self {\n            protocol_version,\n            server_version,\n            connection_id,\n            server_default_collation: collation,\n            status,\n            server_capabilities: capabilities,\n            auth_plugin,\n            auth_plugin_data: auth_plugin_data_1.chain(auth_plugin_data_2),\n        })\n    }\n}\n\n#[test]\nfn test_decode_handshake_mysql_8_0_18() {\n    const HANDSHAKE_MYSQL_8_0_18: &[u8] = b\"\\n8.0.18\\x00\\x19\\x00\\x00\\x00\\x114aB0c\\x06g\\x00\\xff\\xff\\xff\\x02\\x00\\xff\\xc7\\x15\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00tL\\x03s\\x0f[4\\rl4. \\x00caching_sha2_password\\x00\";\n\n    let p = Handshake::decode(HANDSHAKE_MYSQL_8_0_18.into()).unwrap();\n\n    assert_eq!(p.protocol_version, 10);\n\n    assert_eq!(\n        p.server_capabilities,\n        Capabilities::MYSQL\n            | Capabilities::FOUND_ROWS\n            | Capabilities::LONG_FLAG\n            | Capabilities::CONNECT_WITH_DB\n            | Capabilities::NO_SCHEMA\n            | Capabilities::COMPRESS\n            | Capabilities::ODBC\n            | Capabilities::LOCAL_FILES\n            | Capabilities::IGNORE_SPACE\n            | Capabilities::PROTOCOL_41\n            | Capabilities::INTERACTIVE\n            | Capabilities::SSL\n            | Capabilities::TRANSACTIONS\n            | Capabilities::SECURE_CONNECTION\n            | Capabilities::MULTI_STATEMENTS\n            | Capabilities::MULTI_RESULTS\n            | Capabilities::PS_MULTI_RESULTS\n            | Capabilities::PLUGIN_AUTH\n            | Capabilities::CONNECT_ATTRS\n            | Capabilities::PLUGIN_AUTH_LENENC_DATA\n            | Capabilities::CAN_HANDLE_EXPIRED_PASSWORDS\n            | Capabilities::SESSION_TRACK\n            | Capabilities::DEPRECATE_EOF\n            | Capabilities::ZSTD_COMPRESSION_ALGORITHM\n            | Capabilities::SSL_VERIFY_SERVER_CERT\n            | Capabilities::OPTIONAL_RESULTSET_METADATA\n            | Capabilities::REMEMBER_OPTIONS,\n    );\n\n    assert_eq!(p.server_default_collation, 255);\n    assert!(p.status.contains(Status::SERVER_STATUS_AUTOCOMMIT));\n\n    assert!(matches!(\n        p.auth_plugin,\n        Some(AuthPlugin::CachingSha2Password)\n    ));\n\n    assert_eq!(\n        &*p.auth_plugin_data.into_iter().collect::<Vec<_>>(),\n        &[17, 52, 97, 66, 48, 99, 6, 103, 116, 76, 3, 115, 15, 91, 52, 13, 108, 52, 46, 32,]\n    );\n}\n\n#[test]\nfn test_decode_handshake_mariadb_10_4_7() {\n    const HANDSHAKE_MARIA_DB_10_4_7: &[u8] = b\"\\n5.5.5-10.4.7-MariaDB-1:10.4.7+maria~bionic\\x00\\x0b\\x00\\x00\\x00t6L\\\\j\\\"dS\\x00\\xfe\\xf7\\x08\\x02\\x00\\xff\\x81\\x15\\x00\\x00\\x00\\x00\\x00\\x00\\x07\\x00\\x00\\x00U14Oph9\\\"<H5n\\x00mysql_native_password\\x00\";\n\n    let p = Handshake::decode(HANDSHAKE_MARIA_DB_10_4_7.into()).unwrap();\n\n    assert_eq!(p.protocol_version, 10);\n\n    assert_eq!(\n        &*p.server_version,\n        \"5.5.5-10.4.7-MariaDB-1:10.4.7+maria~bionic\"\n    );\n\n    assert_eq!(\n        p.server_capabilities,\n        Capabilities::FOUND_ROWS\n            | Capabilities::LONG_FLAG\n            | Capabilities::CONNECT_WITH_DB\n            | Capabilities::NO_SCHEMA\n            | Capabilities::COMPRESS\n            | Capabilities::ODBC\n            | Capabilities::LOCAL_FILES\n            | Capabilities::IGNORE_SPACE\n            | Capabilities::PROTOCOL_41\n            | Capabilities::INTERACTIVE\n            | Capabilities::TRANSACTIONS\n            | Capabilities::SECURE_CONNECTION\n            | Capabilities::MULTI_STATEMENTS\n            | Capabilities::MULTI_RESULTS\n            | Capabilities::PS_MULTI_RESULTS\n            | Capabilities::PLUGIN_AUTH\n            | Capabilities::CONNECT_ATTRS\n            | Capabilities::PLUGIN_AUTH_LENENC_DATA\n            | Capabilities::CAN_HANDLE_EXPIRED_PASSWORDS\n            | Capabilities::SESSION_TRACK\n            | Capabilities::DEPRECATE_EOF\n            | Capabilities::REMEMBER_OPTIONS\n            | Capabilities::MARIADB_CLIENT_PROGRESS\n            | Capabilities::MARIADB_CLIENT_MULTI\n            | Capabilities::MARIADB_CLIENT_STMT_BULK_OPERATIONS\n    );\n\n    assert_eq!(p.server_default_collation, 8);\n    assert!(p.status.contains(Status::SERVER_STATUS_AUTOCOMMIT));\n    assert!(matches!(\n        p.auth_plugin,\n        Some(AuthPlugin::MySqlNativePassword)\n    ));\n\n    assert_eq!(\n        &*p.auth_plugin_data.into_iter().collect::<Vec<_>>(),\n        &[116, 54, 76, 92, 106, 34, 100, 83, 85, 49, 52, 79, 112, 104, 57, 34, 60, 72, 53, 110,]\n    );\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/connect/handshake_response.rs",
    "content": "use crate::io::MySqlBufMutExt;\nuse crate::io::{BufMutExt, ProtocolEncode};\nuse crate::protocol::auth::AuthPlugin;\nuse crate::protocol::connect::ssl_request::SslRequest;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse\n// https://mariadb.com/kb/en/connection/#client-handshake-response\n\n#[derive(Debug)]\npub struct HandshakeResponse<'a> {\n    pub database: Option<&'a str>,\n\n    /// Max size of a command packet that the client wants to send to the server\n    pub max_packet_size: u32,\n\n    /// Default charset (collation ID < 256) for the connection\n    pub charset: u8,\n\n    /// Name of the SQL account which client wants to log in\n    pub username: &'a str,\n\n    /// Authentication method used by the client\n    pub auth_plugin: Option<AuthPlugin>,\n\n    /// Opaque authentication response\n    pub auth_response: Option<&'a [u8]>,\n}\n\nimpl ProtocolEncode<'_, Capabilities> for HandshakeResponse<'_> {\n    fn encode_with(\n        &self,\n        buf: &mut Vec<u8>,\n        mut context: Capabilities,\n    ) -> Result<(), crate::Error> {\n        if self.auth_plugin.is_none() {\n            // ensure PLUGIN_AUTH is set *only* if we have a defined plugin\n            context.remove(Capabilities::PLUGIN_AUTH);\n        }\n\n        // NOTE: Half of this packet is identical to the SSL Request packet\n        SslRequest {\n            max_packet_size: self.max_packet_size,\n            charset: self.charset,\n        }\n        .encode_with(buf, context)?;\n\n        buf.put_str_nul(self.username);\n\n        if context.contains(Capabilities::PLUGIN_AUTH_LENENC_DATA) {\n            buf.put_bytes_lenenc(self.auth_response.unwrap_or_default());\n        } else if context.contains(Capabilities::SECURE_CONNECTION) {\n            let response = self.auth_response.unwrap_or_default();\n\n            let response_len = u8::try_from(response.len())\n                .map_err(|_| err_protocol!(\"auth_response.len() too long: {}\", response.len()))?;\n\n            buf.push(response_len);\n            buf.extend(response);\n        } else {\n            buf.push(0);\n        }\n\n        if context.contains(Capabilities::CONNECT_WITH_DB) {\n            if let Some(database) = &self.database {\n                buf.put_str_nul(database);\n            } else {\n                buf.push(0);\n            }\n        }\n\n        if context.contains(Capabilities::PLUGIN_AUTH) {\n            if let Some(plugin) = &self.auth_plugin {\n                buf.put_str_nul(plugin.name());\n            } else {\n                buf.push(0);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/connect/mod.rs",
    "content": "//! Connection Phase\n//!\n//! <https://dev.mysql.com/doc/internals/en/connection-phase.html>\n\nmod auth_switch;\nmod handshake;\nmod handshake_response;\nmod ssl_request;\n\npub(crate) use auth_switch::{AuthSwitchRequest, AuthSwitchResponse};\npub(crate) use handshake::Handshake;\npub(crate) use handshake_response::HandshakeResponse;\npub(crate) use ssl_request::SslRequest;\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/connect/ssl_request.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_connection_phase_packets_protocol_handshake_response.html\n// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::SSLRequest\n\n#[derive(Debug)]\npub struct SslRequest {\n    pub max_packet_size: u32,\n    pub charset: u8,\n}\n\nimpl ProtocolEncode<'_, Capabilities> for SslRequest {\n    fn encode_with(&self, buf: &mut Vec<u8>, context: Capabilities) -> Result<(), crate::Error> {\n        // truncation is intended\n        #[allow(clippy::cast_possible_truncation)]\n        buf.extend(&(context.bits() as u32).to_le_bytes());\n        buf.extend(&self.max_packet_size.to_le_bytes());\n        buf.push(self.charset);\n\n        // reserved: string<19>\n        buf.extend(&[0_u8; 19]);\n\n        if context.contains(Capabilities::MYSQL) {\n            // reserved: string<4>\n            buf.extend(&[0_u8; 4]);\n        } else {\n            // extended client capabilities (MariaDB-specified): int<4>\n            buf.extend(&((context.bits() >> 32) as u32).to_le_bytes());\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/mod.rs",
    "content": "pub(crate) mod auth;\nmod capabilities;\npub(crate) mod connect;\nmod packet;\npub(crate) mod response;\nmod row;\npub(crate) mod statement;\npub(crate) mod text;\n\npub(crate) use capabilities::Capabilities;\npub(crate) use packet::Packet;\npub(crate) use row::Row;\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/packet.rs",
    "content": "use std::cmp::min;\nuse std::ops::{Deref, DerefMut};\n\nuse bytes::Bytes;\n\nuse crate::error::Error;\nuse crate::io::{ProtocolDecode, ProtocolEncode};\nuse crate::protocol::response::{EofPacket, OkPacket};\nuse crate::protocol::Capabilities;\n\n#[derive(Debug)]\npub struct Packet<T>(pub(crate) T);\n\nimpl<'en, 'stream, T> ProtocolEncode<'stream, (Capabilities, &'stream mut u8)> for Packet<T>\nwhere\n    T: ProtocolEncode<'en, Capabilities>,\n{\n    fn encode_with(\n        &self,\n        buf: &mut Vec<u8>,\n        (capabilities, sequence_id): (Capabilities, &'stream mut u8),\n    ) -> Result<(), Error> {\n        let mut next_header = |len: u32| {\n            let mut buf = len.to_le_bytes();\n            buf[3] = *sequence_id;\n            *sequence_id = sequence_id.wrapping_add(1);\n\n            buf\n        };\n\n        // reserve space to write the prefixed length\n        let offset = buf.len();\n        buf.extend(&[0_u8; 4]);\n\n        // encode the payload\n        self.0.encode_with(buf, capabilities)?;\n\n        // determine the length of the encoded payload\n        // and write to our reserved space\n        let len = buf.len() - offset - 4;\n        let header = &mut buf[offset..];\n\n        // // `min(.., 0xFF_FF_FF)` cannot overflow\n        #[allow(clippy::cast_possible_truncation)]\n        header[..4].copy_from_slice(&next_header(min(len, 0xFF_FF_FF) as u32));\n\n        // add more packets if we need to split the data\n        if len >= 0xFF_FF_FF {\n            let rest = buf.split_off(offset + 4 + 0xFF_FF_FF);\n            let mut chunks = rest.chunks_exact(0xFF_FF_FF);\n\n            for chunk in chunks.by_ref() {\n                buf.reserve(chunk.len() + 4);\n\n                // `chunk.len() == 0xFF_FF_FF`\n                #[allow(clippy::cast_possible_truncation)]\n                buf.extend(&next_header(chunk.len() as u32));\n                buf.extend(chunk);\n            }\n\n            // this will also handle adding a zero sized packet if the data size is a multiple of 0xFF_FF_FF\n            let remainder = chunks.remainder();\n            buf.reserve(remainder.len() + 4);\n\n            // `remainder.len() < 0xFF_FF_FF`\n            #[allow(clippy::cast_possible_truncation)]\n            buf.extend(&next_header(remainder.len() as u32));\n            buf.extend(remainder);\n        }\n\n        Ok(())\n    }\n}\n\nimpl Packet<Bytes> {\n    pub(crate) fn decode<'de, T>(self) -> Result<T, Error>\n    where\n        T: ProtocolDecode<'de, ()>,\n    {\n        self.decode_with(())\n    }\n\n    pub(crate) fn decode_with<'de, T, C>(self, context: C) -> Result<T, Error>\n    where\n        T: ProtocolDecode<'de, C>,\n    {\n        T::decode_with(self.0, context)\n    }\n\n    pub(crate) fn ok(self) -> Result<OkPacket, Error> {\n        self.decode()\n    }\n\n    pub(crate) fn eof(self, capabilities: Capabilities) -> Result<EofPacket, Error> {\n        if capabilities.contains(Capabilities::DEPRECATE_EOF) {\n            let ok = self.ok()?;\n\n            Ok(EofPacket {\n                warnings: ok.warnings,\n                status: ok.status,\n            })\n        } else {\n            self.decode_with(capabilities)\n        }\n    }\n}\n\nimpl Deref for Packet<Bytes> {\n    type Target = Bytes;\n\n    fn deref(&self) -> &Bytes {\n        &self.0\n    }\n}\n\nimpl DerefMut for Packet<Bytes> {\n    fn deref_mut(&mut self) -> &mut Bytes {\n        &mut self.0\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/response/eof.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::ProtocolDecode;\nuse crate::protocol::response::Status;\nuse crate::protocol::Capabilities;\n\n/// Marks the end of a result set, returning status and warnings.\n///\n/// # Note\n///\n/// The EOF packet is deprecated as of MySQL 5.7.5. SQLx only uses this packet for MySQL\n/// prior MySQL versions.\n#[derive(Debug)]\npub struct EofPacket {\n    #[allow(dead_code)]\n    pub warnings: u16,\n    pub status: Status,\n}\n\nimpl ProtocolDecode<'_, Capabilities> for EofPacket {\n    fn decode_with(mut buf: Bytes, _: Capabilities) -> Result<Self, Error> {\n        let header = buf.get_u8();\n        if header != 0xfe {\n            return Err(err_protocol!(\n                \"expected 0xfe (EOF_Packet) but found 0x{:x}\",\n                header\n            ));\n        }\n\n        let warnings = buf.get_u16_le();\n        let status = Status::from_bits_truncate(buf.get_u16_le());\n\n        Ok(Self { status, warnings })\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/response/err.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::{BufExt, ProtocolDecode};\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_basic_err_packet.html\n// https://mariadb.com/kb/en/err_packet/\n\n/// Indicates that an error occurred.\n#[derive(Debug)]\npub struct ErrPacket {\n    pub error_code: u16,\n    pub sql_state: Option<String>,\n    pub error_message: String,\n}\n\nimpl ProtocolDecode<'_, Capabilities> for ErrPacket {\n    fn decode_with(mut buf: Bytes, capabilities: Capabilities) -> Result<Self, Error> {\n        let header = buf.get_u8();\n        if header != 0xff {\n            return Err(err_protocol!(\n                \"expected 0xff (ERR_Packet) but found 0x{:x}\",\n                header\n            ));\n        }\n\n        let error_code = buf.get_u16_le();\n        let mut sql_state = None;\n\n        if capabilities.contains(Capabilities::PROTOCOL_41) {\n            // If the next byte is '#' then we have a SQL STATE\n            if buf.starts_with(b\"#\") {\n                buf.advance(1);\n                sql_state = Some(buf.get_str(5)?);\n            }\n        }\n\n        let error_message = buf.get_str(buf.len())?;\n\n        Ok(Self {\n            error_code,\n            sql_state,\n            error_message,\n        })\n    }\n}\n\n#[test]\nfn test_decode_err_packet_out_of_order() {\n    const ERR_PACKETS_OUT_OF_ORDER: &[u8] = b\"\\xff\\x84\\x04Got packets out of order\";\n\n    let p =\n        ErrPacket::decode_with(ERR_PACKETS_OUT_OF_ORDER.into(), Capabilities::PROTOCOL_41).unwrap();\n\n    assert_eq!(&p.error_message, \"Got packets out of order\");\n    assert_eq!(p.error_code, 1156);\n    assert_eq!(p.sql_state, None);\n}\n\n#[test]\nfn test_decode_err_packet_unknown_database() {\n    const ERR_HANDSHAKE_UNKNOWN_DB: &[u8] = b\"\\xff\\x19\\x04#42000Unknown database \\'unknown\\'\";\n\n    let p =\n        ErrPacket::decode_with(ERR_HANDSHAKE_UNKNOWN_DB.into(), Capabilities::PROTOCOL_41).unwrap();\n\n    assert_eq!(p.error_code, 1049);\n    assert_eq!(p.sql_state.as_deref(), Some(\"42000\"));\n    assert_eq!(&p.error_message, \"Unknown database \\'unknown\\'\");\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/response/mod.rs",
    "content": "//! Generic Response Packets\n//!\n//! <https://dev.mysql.com/doc/internals/en/generic-response-packets.html>\n//! <https://mariadb.com/kb/en/4-server-response-packets/>\n\nmod eof;\nmod err;\nmod ok;\nmod status;\n\npub use eof::EofPacket;\npub use err::ErrPacket;\npub use ok::OkPacket;\npub use status::Status;\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/response/ok.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::MySqlBufExt;\nuse crate::io::ProtocolDecode;\nuse crate::protocol::response::Status;\n\n/// Indicates successful completion of a previous command sent by the client.\n#[derive(Debug)]\npub struct OkPacket {\n    pub affected_rows: u64,\n    pub last_insert_id: u64,\n    pub status: Status,\n    pub warnings: u16,\n}\n\nimpl ProtocolDecode<'_> for OkPacket {\n    fn decode_with(mut buf: Bytes, _: ()) -> Result<Self, Error> {\n        let header = buf.get_u8();\n        if header != 0 && header != 0xfe {\n            return Err(err_protocol!(\n                \"expected 0x00 or 0xfe (OK_Packet) but found 0x{:02x}\",\n                header\n            ));\n        }\n\n        let affected_rows = buf.get_uint_lenenc()?;\n        let last_insert_id = buf.get_uint_lenenc()?;\n\n        if buf.remaining() < 4 {\n            return Err(err_protocol!(\n                \"OK_Packet too short: expected at least 4 more bytes for status+warnings, got {}\",\n                buf.remaining()\n            ));\n        }\n\n        let status = Status::from_bits_truncate(buf.get_u16_le());\n        let warnings = buf.get_u16_le();\n\n        Ok(Self {\n            affected_rows,\n            last_insert_id,\n            status,\n            warnings,\n        })\n    }\n}\n\n#[test]\nfn test_decode_ok_packet() {\n    const DATA: &[u8] = b\"\\x00\\x00\\x00\\x02@\\x00\\x00\";\n\n    let p = OkPacket::decode(DATA.into()).unwrap();\n\n    assert_eq!(p.affected_rows, 0);\n    assert_eq!(p.last_insert_id, 0);\n    assert_eq!(p.warnings, 0);\n    assert!(p.status.contains(Status::SERVER_STATUS_AUTOCOMMIT));\n    assert!(p.status.contains(Status::SERVER_SESSION_STATE_CHANGED));\n}\n\n#[test]\nfn test_decode_ok_packet_with_info() {\n    // OK packet with 0xfe header and length >= 9 (with appended info)\n    const DATA: &[u8] = b\"\\xfe\\x01\\x00\\x02\\x00\\x00\\x00\\x05\\x09info data\";\n\n    let p = OkPacket::decode(DATA.into()).unwrap();\n\n    assert_eq!(p.affected_rows, 1);\n    assert_eq!(p.last_insert_id, 0);\n    assert_eq!(p.warnings, 0);\n    assert!(p.status.contains(Status::SERVER_STATUS_AUTOCOMMIT));\n}\n\n#[test]\nfn test_decode_ok_packet_with_extended_info() {\n    // OK packet with 0xfe header, affected rows, last insert id, and extended info\n    const DATA: &[u8] = b\"\\xfe\\x05\\x64\\x02\\x00\\x01\\x00\\x0e\\x14extended information\";\n\n    let p = OkPacket::decode(DATA.into()).unwrap();\n\n    assert_eq!(p.affected_rows, 5);\n    assert_eq!(p.last_insert_id, 100);\n    assert_eq!(p.warnings, 1);\n    assert!(p.status.contains(Status::SERVER_STATUS_AUTOCOMMIT));\n}\n\n#[test]\nfn test_decode_ok_packet_truncated() {\n    const DATA: &[u8] = b\"\\x00\\x00\\x00\\x01\";\n\n    let err = OkPacket::decode(DATA.into()).unwrap_err();\n    assert!(matches!(err, Error::Protocol(_)), \"{err}\");\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/response/status.rs",
    "content": "// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/mysql__com_8h.html#a1d854e841086925be1883e4d7b4e8cad\n// https://mariadb.com/kb/en/library/mariadb-connectorc-types-and-definitions/#server-status\nbitflags::bitflags! {\n    #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]\n    pub struct Status: u16 {\n        // Is raised when a multi-statement transaction has been started, either explicitly,\n        // by means of BEGIN or COMMIT AND CHAIN, or implicitly, by the first\n        // transactional statement, when autocommit=off.\n        const SERVER_STATUS_IN_TRANS = 1;\n\n        // Autocommit mode is set\n        const SERVER_STATUS_AUTOCOMMIT = 2;\n\n        // Multi query - next query exists.\n        const SERVER_MORE_RESULTS_EXISTS = 8;\n\n        const SERVER_QUERY_NO_GOOD_INDEX_USED = 16;\n        const SERVER_QUERY_NO_INDEX_USED = 32;\n\n        // When using COM_STMT_FETCH, indicate that current cursor still has result\n        const SERVER_STATUS_CURSOR_EXISTS = 64;\n\n        // When using COM_STMT_FETCH, indicate that current cursor has finished to send results\n        const SERVER_STATUS_LAST_ROW_SENT = 128;\n\n        // Database has been dropped\n        const SERVER_STATUS_DB_DROPPED = (1 << 8);\n\n        // Current escape mode is \"no backslash escape\"\n        const SERVER_STATUS_NO_BACKSLASH_ESCAPES = (1 << 9);\n\n        // A DDL change did have an impact on an existing PREPARE (an automatic\n        // re-prepare has been executed)\n        const SERVER_STATUS_METADATA_CHANGED = (1 << 10);\n\n        // Last statement took more than the time value specified\n        // in server variable long_query_time.\n        const SERVER_QUERY_WAS_SLOW = (1 << 11);\n\n        // This result-set contain stored procedure output parameter.\n        const SERVER_PS_OUT_PARAMS = (1 << 12);\n\n        // Current transaction is a read-only transaction.\n        const SERVER_STATUS_IN_TRANS_READONLY = (1 << 13);\n\n        // This status flag, when on, implies that one of the state information has changed\n        // on the server because of the execution of the last statement.\n        const SERVER_SESSION_STATE_CHANGED = (1 << 14);\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/row.rs",
    "content": "use std::ops::Range;\n\nuse bytes::Bytes;\n\n#[derive(Debug)]\npub(crate) struct Row {\n    pub(crate) storage: Bytes,\n    pub(crate) values: Vec<Option<Range<usize>>>,\n}\n\nimpl Row {\n    pub(crate) fn get(&self, index: usize) -> Option<&[u8]> {\n        self.values[index].clone().map(|col| &self.storage[col])\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/statement/execute.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::text::ColumnFlags;\nuse crate::protocol::Capabilities;\nuse crate::MySqlArguments;\n\n// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_com_stmt_execute.html\n\n#[derive(Debug)]\npub struct Execute<'q> {\n    pub statement: u32,\n    pub arguments: &'q MySqlArguments,\n}\n\nimpl ProtocolEncode<'_, Capabilities> for Execute<'_> {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), crate::Error> {\n        buf.push(0x17); // COM_STMT_EXECUTE\n        buf.extend(&self.statement.to_le_bytes());\n        buf.push(0); // NO_CURSOR\n        buf.extend(&1_u32.to_le_bytes()); // iterations (always 1): int<4>\n\n        if !self.arguments.types.is_empty() {\n            buf.extend_from_slice(&self.arguments.null_bitmap);\n            buf.push(1); // send type to server\n\n            for ty in &self.arguments.types {\n                buf.push(ty.r#type as u8);\n\n                buf.push(if ty.flags.contains(ColumnFlags::UNSIGNED) {\n                    0x80\n                } else {\n                    0\n                });\n            }\n\n            buf.extend(&*self.arguments.values);\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/statement/mod.rs",
    "content": "mod execute;\nmod prepare;\nmod prepare_ok;\nmod row;\nmod stmt_close;\n\npub(crate) use execute::Execute;\npub(crate) use prepare::Prepare;\npub(crate) use prepare_ok::PrepareOk;\npub(crate) use row::BinaryRow;\npub(crate) use stmt_close::StmtClose;\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/statement/prepare.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/com-stmt-prepare.html#packet-COM_STMT_PREPARE\n\npub struct Prepare<'a> {\n    pub query: &'a str,\n}\n\nimpl ProtocolEncode<'_, Capabilities> for Prepare<'_> {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), crate::Error> {\n        buf.push(0x16); // COM_STMT_PREPARE\n        buf.extend(self.query.as_bytes());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/statement/prepare_ok.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::ProtocolDecode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/com-stmt-prepare-response.html#packet-COM_STMT_PREPARE_OK\n\n#[derive(Debug)]\npub(crate) struct PrepareOk {\n    pub(crate) statement_id: u32,\n    pub(crate) columns: u16,\n    pub(crate) params: u16,\n    #[allow(unused)]\n    pub(crate) warnings: u16,\n}\n\nimpl ProtocolDecode<'_, Capabilities> for PrepareOk {\n    fn decode_with(buf: Bytes, _: Capabilities) -> Result<Self, Error> {\n        const SIZE: usize = 12;\n\n        let mut slice = buf.get(..SIZE).ok_or_else(|| {\n            err_protocol!(\"PrepareOk expected 12 bytes but got {} bytes\", buf.len())\n        })?;\n\n        let status = slice.get_u8();\n        if status != 0x00 {\n            return Err(err_protocol!(\n                \"expected 0x00 (COM_STMT_PREPARE_OK) but found 0x{:02x}\",\n                status\n            ));\n        }\n\n        let statement_id = slice.get_u32_le();\n        let columns = slice.get_u16_le();\n        let params = slice.get_u16_le();\n\n        slice.advance(1); // reserved: string<1>\n\n        let warnings = slice.get_u16_le();\n\n        Ok(Self {\n            statement_id,\n            columns,\n            params,\n            warnings,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/statement/row.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::MySqlBufExt;\nuse crate::io::{BufExt, ProtocolDecode};\nuse crate::protocol::text::ColumnType;\nuse crate::protocol::Row;\nuse crate::MySqlColumn;\n\n// https://dev.mysql.com/doc/internals/en/binary-protocol-resultset-row.html#packet-ProtocolBinary::ResultsetRow\n// https://dev.mysql.com/doc/internals/en/binary-protocol-value.html\n\n#[derive(Debug)]\npub(crate) struct BinaryRow(pub(crate) Row);\n\nimpl<'de> ProtocolDecode<'de, &'de [MySqlColumn]> for BinaryRow {\n    fn decode_with(mut buf: Bytes, columns: &'de [MySqlColumn]) -> Result<Self, Error> {\n        let header = buf.get_u8();\n        if header != 0 {\n            return Err(err_protocol!(\n                \"expected 0x00 (ROW) but found 0x{:02x}\",\n                header\n            ));\n        }\n\n        let storage = buf.clone();\n        let offset = buf.len();\n\n        let null_bitmap_len = (columns.len() + 9) / 8;\n        let null_bitmap = buf.get_bytes(null_bitmap_len);\n\n        let mut values = Vec::with_capacity(columns.len());\n\n        for (column_idx, column) in columns.iter().enumerate() {\n            // NOTE: the column index starts at the 3rd bit\n            let column_null_idx = column_idx + 2;\n\n            let byte_idx = column_null_idx / 8;\n            let bit_idx = column_null_idx % 8;\n\n            let is_null = null_bitmap[byte_idx] & (1u8 << bit_idx) != 0;\n\n            if is_null {\n                values.push(None);\n                continue;\n            }\n\n            // NOTE: MySQL will never generate NULL types for non-NULL values\n            let type_info = &column.type_info;\n\n            // Unlike Postgres, MySQL does not length-prefix every value in a binary row.\n            // Values are *either* fixed-length or length-prefixed,\n            // so we need to inspect the type code to be sure.\n            let size: usize = match type_info.r#type {\n                // All fixed-length types.\n                ColumnType::LongLong => 8,\n                ColumnType::Long | ColumnType::Int24 => 4,\n                ColumnType::Short | ColumnType::Year => 2,\n                ColumnType::Tiny => 1,\n                ColumnType::Float => 4,\n                ColumnType::Double => 8,\n\n                // Blobs and strings are prefixed with their length,\n                // which is itself a length-encoded integer.\n                ColumnType::String\n                | ColumnType::VarChar\n                | ColumnType::VarString\n                | ColumnType::Enum\n                | ColumnType::Set\n                | ColumnType::LongBlob\n                | ColumnType::MediumBlob\n                | ColumnType::Blob\n                | ColumnType::TinyBlob\n                | ColumnType::Geometry\n                | ColumnType::Bit\n                | ColumnType::Decimal\n                | ColumnType::Json\n                | ColumnType::NewDecimal => {\n                    let size = buf.get_uint_lenenc()?;\n                    usize::try_from(size)\n                        .map_err(|_| err_protocol!(\"BLOB length out of range: {size}\"))?\n                }\n\n                // Like strings and blobs, these values are variable-length.\n                // Unlike strings and blobs, however, they exclusively use one byte for length.\n                ColumnType::Time\n                | ColumnType::Timestamp\n                | ColumnType::Date\n                | ColumnType::Datetime => {\n                    // Leave the length byte on the front of the value because decoding uses it.\n                    buf[0] as usize + 1\n                }\n\n                // NOTE: MySQL will never generate NULL types for non-NULL values\n                ColumnType::Null => unreachable!(),\n            };\n\n            let offset = offset - buf.len();\n\n            values.push(Some(offset..(offset + size)));\n\n            buf.advance(size);\n        }\n\n        Ok(BinaryRow(Row { values, storage }))\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/statement/stmt_close.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/com-stmt-close.html\n\n#[derive(Debug)]\npub struct StmtClose {\n    pub statement: u32,\n}\n\nimpl ProtocolEncode<'_, Capabilities> for StmtClose {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), crate::Error> {\n        buf.push(0x19); // COM_STMT_CLOSE\n        buf.extend(&self.statement.to_le_bytes());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/text/column.rs",
    "content": "use std::str;\n\nuse crate::collation::Collation;\nuse crate::error::Error;\nuse crate::io::MySqlBufExt;\nuse crate::io::ProtocolDecode;\nuse crate::protocol::Capabilities;\nuse bitflags::bitflags;\nuse bytes::{Buf, Bytes};\n\n// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/group__group__cs__column__definition__flags.html\n\nbitflags! {\n    #[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\n    pub(crate) struct ColumnFlags: u16 {\n        /// Field can't be `NULL`.\n        const NOT_NULL = 1;\n\n        /// Field is part of a primary key.\n        const PRIMARY_KEY = 2;\n\n        /// Field is part of a unique key.\n        const UNIQUE_KEY = 4;\n\n        /// Field is part of a multi-part unique or primary key.\n        const MULTIPLE_KEY = 8;\n\n        /// Field is a blob.\n        const BLOB = 16;\n\n        /// Field is unsigned.\n        const UNSIGNED = 32;\n\n        /// Field is zero filled.\n        const ZEROFILL = 64;\n\n        /// Field is binary.\n        const BINARY = 128;\n\n        /// Field is an enumeration.\n        const ENUM = 256;\n\n        /// Field is an auto-increment field.\n        const AUTO_INCREMENT = 512;\n\n        /// Field is a timestamp.\n        const TIMESTAMP = 1024;\n\n        /// Field is a set.\n        const SET = 2048;\n\n        /// Field does not have a default value.\n        const NO_DEFAULT_VALUE = 4096;\n\n        /// Field is set to NOW on UPDATE.\n        const ON_UPDATE_NOW = 8192;\n\n        /// Field is a number.\n        const NUM = 32768;\n    }\n}\n\n// https://dev.mysql.com/doc/internals/en/com-query-response.html#column-type\n\n#[derive(Debug, Copy, Clone, PartialEq)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\n#[repr(u8)]\npub enum ColumnType {\n    Decimal = 0x00,\n    Tiny = 0x01,\n    Short = 0x02,\n    Long = 0x03,\n    Float = 0x04,\n    Double = 0x05,\n    Null = 0x06,\n    Timestamp = 0x07,\n    LongLong = 0x08,\n    Int24 = 0x09,\n    Date = 0x0a,\n    Time = 0x0b,\n    Datetime = 0x0c,\n    Year = 0x0d,\n    VarChar = 0x0f,\n    Bit = 0x10,\n    Json = 0xf5,\n    NewDecimal = 0xf6,\n    Enum = 0xf7,\n    Set = 0xf8,\n    TinyBlob = 0xf9,\n    MediumBlob = 0xfa,\n    LongBlob = 0xfb,\n    Blob = 0xfc,\n    VarString = 0xfd,\n    String = 0xfe,\n    Geometry = 0xff,\n}\n\n// https://dev.mysql.com/doc/dev/mysql-server/8.0.12/page_protocol_com_query_response_text_resultset_column_definition.html\n// https://mariadb.com/kb/en/resultset/#column-definition-packet\n// https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnDefinition41\n\n#[derive(Debug)]\npub(crate) struct ColumnDefinition {\n    #[allow(unused)]\n    catalog: Bytes,\n    schema: Bytes,\n    #[allow(unused)]\n    table_alias: Bytes,\n    table: Bytes,\n    alias: Bytes,\n    name: Bytes,\n    pub(crate) collation: Collation,\n    pub(crate) max_size: u32,\n    pub(crate) r#type: ColumnType,\n    pub(crate) flags: ColumnFlags,\n    #[allow(unused)]\n    decimals: u8,\n}\n\nimpl ColumnDefinition {\n    // NOTE: strings in-protocol are transmitted according to the client character set\n    //       as this is UTF-8, all these strings should be UTF-8\n\n    pub(crate) fn schema(&self) -> Result<&str, Error> {\n        str::from_utf8(&self.schema).map_err(Error::protocol)\n    }\n\n    pub(crate) fn table(&self) -> Result<&str, Error> {\n        str::from_utf8(&self.table).map_err(Error::protocol)\n    }\n\n    pub(crate) fn name(&self) -> Result<&str, Error> {\n        str::from_utf8(&self.name).map_err(Error::protocol)\n    }\n\n    pub(crate) fn alias(&self) -> Result<&str, Error> {\n        str::from_utf8(&self.alias).map_err(Error::protocol)\n    }\n}\n\nimpl ProtocolDecode<'_, Capabilities> for ColumnDefinition {\n    fn decode_with(mut buf: Bytes, _: Capabilities) -> Result<Self, Error> {\n        let catalog = buf.get_bytes_lenenc()?;\n        let schema = buf.get_bytes_lenenc()?;\n        let table_alias = buf.get_bytes_lenenc()?;\n        let table = buf.get_bytes_lenenc()?;\n        let alias = buf.get_bytes_lenenc()?;\n        let name = buf.get_bytes_lenenc()?;\n        let _next_len = buf.get_uint_lenenc()?; // always 0x0c\n        let collation = buf.get_u16_le();\n        let max_size = buf.get_u32_le();\n        let type_id = buf.get_u8();\n        let flags = buf.get_u16_le();\n        let decimals = buf.get_u8();\n\n        Ok(Self {\n            catalog,\n            schema,\n            table_alias,\n            table,\n            alias,\n            name,\n            collation: Collation(collation),\n            max_size,\n            r#type: ColumnType::try_from_u16(type_id)?,\n            flags: ColumnFlags::from_bits_truncate(flags),\n            decimals,\n        })\n    }\n}\n\nimpl ColumnType {\n    pub(crate) fn name(self, flags: ColumnFlags, max_size: Option<u32>) -> &'static str {\n        let is_binary = flags.contains(ColumnFlags::BINARY);\n        let is_unsigned = flags.contains(ColumnFlags::UNSIGNED);\n        let is_enum = flags.contains(ColumnFlags::ENUM);\n\n        match self {\n            ColumnType::Tiny if max_size == Some(1) => \"BOOLEAN\",\n            ColumnType::Tiny if is_unsigned => \"TINYINT UNSIGNED\",\n            ColumnType::Short if is_unsigned => \"SMALLINT UNSIGNED\",\n            ColumnType::Long if is_unsigned => \"INT UNSIGNED\",\n            ColumnType::Int24 if is_unsigned => \"MEDIUMINT UNSIGNED\",\n            ColumnType::LongLong if is_unsigned => \"BIGINT UNSIGNED\",\n            ColumnType::Tiny => \"TINYINT\",\n            ColumnType::Short => \"SMALLINT\",\n            ColumnType::Long => \"INT\",\n            ColumnType::Int24 => \"MEDIUMINT\",\n            ColumnType::LongLong => \"BIGINT\",\n            ColumnType::Float => \"FLOAT\",\n            ColumnType::Double => \"DOUBLE\",\n            ColumnType::Null => \"NULL\",\n            ColumnType::Timestamp => \"TIMESTAMP\",\n            ColumnType::Date => \"DATE\",\n            ColumnType::Time => \"TIME\",\n            ColumnType::Datetime => \"DATETIME\",\n            ColumnType::Year => \"YEAR\",\n            ColumnType::Bit => \"BIT\",\n            ColumnType::Enum => \"ENUM\",\n            ColumnType::Set => \"SET\",\n            ColumnType::Decimal | ColumnType::NewDecimal => \"DECIMAL\",\n            ColumnType::Geometry => \"GEOMETRY\",\n            ColumnType::Json => \"JSON\",\n\n            ColumnType::String if is_binary => \"BINARY\",\n            ColumnType::String if is_enum => \"ENUM\",\n            ColumnType::VarChar | ColumnType::VarString if is_binary => \"VARBINARY\",\n\n            ColumnType::String => \"CHAR\",\n            ColumnType::VarChar | ColumnType::VarString => \"VARCHAR\",\n\n            ColumnType::TinyBlob if is_binary => \"TINYBLOB\",\n            ColumnType::TinyBlob => \"TINYTEXT\",\n\n            ColumnType::Blob if is_binary => \"BLOB\",\n            ColumnType::Blob => \"TEXT\",\n\n            ColumnType::MediumBlob if is_binary => \"MEDIUMBLOB\",\n            ColumnType::MediumBlob => \"MEDIUMTEXT\",\n\n            ColumnType::LongBlob if is_binary => \"LONGBLOB\",\n            ColumnType::LongBlob => \"LONGTEXT\",\n        }\n    }\n\n    pub(crate) fn try_from_u16(id: u8) -> Result<Self, Error> {\n        Ok(match id {\n            0x00 => ColumnType::Decimal,\n            0x01 => ColumnType::Tiny,\n            0x02 => ColumnType::Short,\n            0x03 => ColumnType::Long,\n            0x04 => ColumnType::Float,\n            0x05 => ColumnType::Double,\n            0x06 => ColumnType::Null,\n            0x07 => ColumnType::Timestamp,\n            0x08 => ColumnType::LongLong,\n            0x09 => ColumnType::Int24,\n            0x0a => ColumnType::Date,\n            0x0b => ColumnType::Time,\n            0x0c => ColumnType::Datetime,\n            0x0d => ColumnType::Year,\n            // [internal] 0x0e => ColumnType::NewDate,\n            0x0f => ColumnType::VarChar,\n            0x10 => ColumnType::Bit,\n            // [internal] 0x11 => ColumnType::Timestamp2,\n            // [internal] 0x12 => ColumnType::Datetime2,\n            // [internal] 0x13 => ColumnType::Time2,\n            0xf5 => ColumnType::Json,\n            0xf6 => ColumnType::NewDecimal,\n            0xf7 => ColumnType::Enum,\n            0xf8 => ColumnType::Set,\n            0xf9 => ColumnType::TinyBlob,\n            0xfa => ColumnType::MediumBlob,\n            0xfb => ColumnType::LongBlob,\n            0xfc => ColumnType::Blob,\n            0xfd => ColumnType::VarString,\n            0xfe => ColumnType::String,\n            0xff => ColumnType::Geometry,\n\n            _ => {\n                return Err(err_protocol!(\"unknown column type 0x{:02x}\", id));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/text/mod.rs",
    "content": "mod column;\nmod ping;\nmod query;\nmod quit;\nmod row;\n\npub(crate) use column::{ColumnDefinition, ColumnFlags, ColumnType};\npub(crate) use ping::Ping;\npub(crate) use query::Query;\npub(crate) use quit::Quit;\npub(crate) use row::TextRow;\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/text/ping.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/com-ping.html\n\n#[derive(Debug)]\npub(crate) struct Ping;\n\nimpl ProtocolEncode<'_, Capabilities> for Ping {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), crate::Error> {\n        buf.push(0x0e); // COM_PING\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/text/query.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/com-query.html\n\n#[derive(Debug)]\npub(crate) struct Query<'q>(pub(crate) &'q str);\n\nimpl ProtocolEncode<'_, Capabilities> for Query<'_> {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), crate::Error> {\n        buf.push(0x03); // COM_QUERY\n        buf.extend(self.0.as_bytes());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/text/quit.rs",
    "content": "use crate::io::ProtocolEncode;\nuse crate::protocol::Capabilities;\n\n// https://dev.mysql.com/doc/internals/en/com-quit.html\n\n#[derive(Debug)]\npub(crate) struct Quit;\n\nimpl ProtocolEncode<'_, Capabilities> for Quit {\n    fn encode_with(&self, buf: &mut Vec<u8>, _: Capabilities) -> Result<(), crate::Error> {\n        buf.push(0x01); // COM_QUIT\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/protocol/text/row.rs",
    "content": "use bytes::{Buf, Bytes};\n\nuse crate::column::MySqlColumn;\nuse crate::error::Error;\nuse crate::io::MySqlBufExt;\nuse crate::io::ProtocolDecode;\nuse crate::protocol::Row;\n\n#[derive(Debug)]\npub(crate) struct TextRow(pub(crate) Row);\n\nimpl<'de> ProtocolDecode<'de, &'de [MySqlColumn]> for TextRow {\n    fn decode_with(mut buf: Bytes, columns: &'de [MySqlColumn]) -> Result<Self, Error> {\n        let storage = buf.clone();\n        let offset = buf.len();\n\n        let mut values = Vec::with_capacity(columns.len());\n\n        for c in columns {\n            if buf[0] == 0xfb {\n                // NULL is sent as 0xfb\n                values.push(None);\n                buf.advance(1);\n            } else {\n                let size = buf.get_uint_lenenc()?;\n                if (buf.remaining() as u64) < size {\n                    return Err(err_protocol!(\n                        \"buffer exhausted when reading data for column {:?}; decoded length is {}, but only {} bytes remain in buffer. Malformed packet or protocol error?\",\n                        c,\n                        size,\n                        buf.remaining()));\n                }\n                let size = usize::try_from(size)\n                    .map_err(|_| err_protocol!(\"TextRow length out of range: {size}\"))?;\n\n                let offset = offset - buf.len();\n\n                values.push(Some(offset..(offset + size)));\n\n                buf.advance(size);\n            }\n        }\n\n        Ok(TextRow(Row { values, storage }))\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/query_result.rs",
    "content": "use std::iter::{Extend, IntoIterator};\n\n#[derive(Debug, Default)]\npub struct MySqlQueryResult {\n    pub(super) rows_affected: u64,\n    pub(super) last_insert_id: u64,\n}\n\nimpl MySqlQueryResult {\n    pub fn last_insert_id(&self) -> u64 {\n        self.last_insert_id\n    }\n\n    pub fn rows_affected(&self) -> u64 {\n        self.rows_affected\n    }\n}\n\nimpl Extend<MySqlQueryResult> for MySqlQueryResult {\n    fn extend<T: IntoIterator<Item = MySqlQueryResult>>(&mut self, iter: T) {\n        for elem in iter {\n            self.rows_affected += elem.rows_affected;\n            self.last_insert_id = elem.last_insert_id;\n        }\n    }\n}\n#[cfg(feature = \"any\")]\n/// This conversion attempts to save last_insert_id by converting to i64.\nimpl From<MySqlQueryResult> for sqlx_core::any::AnyQueryResult {\n    fn from(done: MySqlQueryResult) -> Self {\n        sqlx_core::any::AnyQueryResult {\n            rows_affected: done.rows_affected(),\n            last_insert_id: done.last_insert_id().try_into().ok(),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/row.rs",
    "content": "use std::sync::Arc;\n\npub(crate) use sqlx_core::row::*;\n\nuse crate::column::ColumnIndex;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::HashMap;\nuse crate::{protocol, MySql, MySqlColumn, MySqlValueFormat, MySqlValueRef};\n\n/// Implementation of [`Row`] for MySQL.\npub struct MySqlRow {\n    pub(crate) row: protocol::Row,\n    pub(crate) format: MySqlValueFormat,\n    pub(crate) columns: Arc<Vec<MySqlColumn>>,\n    pub(crate) column_names: Arc<HashMap<UStr, usize>>,\n}\n\nimpl Row for MySqlRow {\n    type Database = MySql;\n\n    fn columns(&self) -> &[MySqlColumn] {\n        &self.columns\n    }\n\n    fn try_get_raw<I>(&self, index: I) -> Result<MySqlValueRef<'_>, Error>\n    where\n        I: ColumnIndex<Self>,\n    {\n        let index = index.index(self)?;\n        let column = &self.columns[index];\n        let value = self.row.get(index);\n\n        Ok(MySqlValueRef {\n            format: self.format,\n            row: Some(&self.row.storage),\n            type_info: column.type_info.clone(),\n            value,\n        })\n    }\n}\n\nimpl ColumnIndex<MySqlRow> for &'_ str {\n    fn index(&self, row: &MySqlRow) -> Result<usize, Error> {\n        row.column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n\nimpl std::fmt::Debug for MySqlRow {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        debug_row(self, f)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/statement.rs",
    "content": "use super::MySqlColumn;\nuse crate::column::ColumnIndex;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::HashMap;\nuse crate::{MySql, MySqlArguments, MySqlTypeInfo};\nuse either::Either;\nuse sqlx_core::sql_str::SqlStr;\nuse std::sync::Arc;\n\npub(crate) use sqlx_core::statement::*;\n\n#[derive(Debug, Clone)]\npub struct MySqlStatement {\n    pub(crate) sql: SqlStr,\n    pub(crate) metadata: MySqlStatementMetadata,\n}\n\n#[derive(Debug, Default, Clone)]\npub(crate) struct MySqlStatementMetadata {\n    pub(crate) columns: Arc<Vec<MySqlColumn>>,\n    pub(crate) column_names: Arc<HashMap<UStr, usize>>,\n    pub(crate) parameters: usize,\n}\n\nimpl Statement for MySqlStatement {\n    type Database = MySql;\n\n    fn into_sql(self) -> SqlStr {\n        self.sql\n    }\n\n    fn sql(&self) -> &SqlStr {\n        &self.sql\n    }\n\n    fn parameters(&self) -> Option<Either<&[MySqlTypeInfo], usize>> {\n        Some(Either::Right(self.metadata.parameters))\n    }\n\n    fn columns(&self) -> &[MySqlColumn] {\n        &self.metadata.columns\n    }\n\n    impl_statement_query!(MySqlArguments);\n}\n\nimpl ColumnIndex<MySqlStatement> for &'_ str {\n    fn index(&self, statement: &MySqlStatement) -> Result<usize, Error> {\n        statement\n            .metadata\n            .column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/testing/mod.rs",
    "content": "use std::future::Future;\nuse std::ops::Deref;\nuse std::str::FromStr;\nuse std::sync::OnceLock;\nuse std::time::Duration;\n\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::pool::{Pool, PoolOptions};\nuse crate::query::query;\nuse crate::{MySql, MySqlConnectOptions, MySqlConnection, MySqlDatabaseError};\nuse sqlx_core::connection::Connection;\nuse sqlx_core::query_builder::QueryBuilder;\nuse sqlx_core::query_scalar::query_scalar;\nuse sqlx_core::sql_str::AssertSqlSafe;\n\npub(crate) use sqlx_core::testing::*;\n\n// Using a blocking `OnceLock` here because the critical sections are short.\nstatic MASTER_POOL: OnceLock<Pool<MySql>> = OnceLock::new();\n\nimpl TestSupport for MySql {\n    fn test_context(\n        args: &TestArgs,\n    ) -> impl Future<Output = Result<TestContext<Self>, Error>> + Send + '_ {\n        test_context(args)\n    }\n\n    async fn cleanup_test(db_name: &str) -> Result<(), Error> {\n        let mut conn = MASTER_POOL\n            .get()\n            .expect(\"cleanup_test() invoked outside `#[sqlx::test]`\")\n            .acquire()\n            .await?;\n\n        do_cleanup(&mut conn, db_name).await\n    }\n\n    async fn cleanup_test_dbs() -> Result<Option<usize>, Error> {\n        let url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n\n        let mut conn = MySqlConnection::connect(&url).await?;\n\n        let delete_db_names: Vec<String> = query_scalar(\"select db_name from _sqlx_test_databases\")\n            .fetch_all(&mut conn)\n            .await?;\n\n        if delete_db_names.is_empty() {\n            return Ok(None);\n        }\n\n        let mut deleted_db_names = Vec::with_capacity(delete_db_names.len());\n\n        let mut builder = QueryBuilder::new(\"drop database if exists \");\n\n        for db_name in &delete_db_names {\n            builder.push(db_name);\n\n            match builder.build().execute(&mut conn).await {\n                Ok(_deleted) => {\n                    deleted_db_names.push(db_name);\n                }\n                // Assume a database error just means the DB is still in use.\n                Err(Error::Database(dbe)) => {\n                    eprintln!(\"could not clean test database {db_name:?}: {dbe}\")\n                }\n                // Bubble up other errors\n                Err(e) => return Err(e),\n            }\n\n            builder.reset();\n        }\n\n        if deleted_db_names.is_empty() {\n            return Ok(None);\n        }\n\n        let mut query = QueryBuilder::new(\"delete from _sqlx_test_databases where db_name in (\");\n\n        let mut separated = query.separated(\",\");\n\n        for db_name in &deleted_db_names {\n            separated.push_bind(db_name);\n        }\n\n        query.push(\")\").build().execute(&mut conn).await?;\n\n        let _ = conn.close().await;\n        Ok(Some(delete_db_names.len()))\n    }\n\n    async fn snapshot(_conn: &mut Self::Connection) -> Result<FixtureSnapshot<Self>, Error> {\n        // TODO: I want to get the testing feature out the door so this will have to wait,\n        // but I'm keeping the code around for now because I plan to come back to it.\n        todo!()\n    }\n}\n\nasync fn test_context(args: &TestArgs) -> Result<TestContext<MySql>, Error> {\n    let url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n\n    let master_opts = MySqlConnectOptions::from_str(&url).expect(\"failed to parse DATABASE_URL\");\n\n    let pool = PoolOptions::new()\n        // MySql's normal connection limit is 150 plus 1 superuser connection\n        // We don't want to use the whole cap and there may be fuzziness here due to\n        // concurrently running tests anyway.\n        .max_connections(20)\n        // Immediately close master connections. Tokio's I/O streams don't like hopping runtimes.\n        .after_release(|_conn, _| Box::pin(async move { Ok(false) }))\n        .connect_lazy_with(master_opts);\n\n    let master_pool = match once_lock_try_insert_polyfill(&MASTER_POOL, pool) {\n        Ok(inserted) => inserted,\n        Err((existing, pool)) => {\n            // Sanity checks.\n            assert_eq!(\n                existing.connect_options().host,\n                pool.connect_options().host,\n                \"DATABASE_URL changed at runtime, host differs\"\n            );\n\n            assert_eq!(\n                existing.connect_options().database,\n                pool.connect_options().database,\n                \"DATABASE_URL changed at runtime, database differs\"\n            );\n\n            existing\n        }\n    };\n\n    let mut conn = master_pool.acquire().await?;\n\n    cleanup_old_dbs(&mut conn).await?;\n\n    // language=MySQL\n    conn.execute(\n        r#\"\n        create table if not exists _sqlx_test_databases (\n            db_name text not null,\n            test_path text not null,\n            created_at timestamp not null default current_timestamp,\n            -- BLOB/TEXT columns can only be used as index keys with a prefix length:\n            -- https://dev.mysql.com/doc/refman/8.4/en/column-indexes.html#column-indexes-prefix\n            primary key(db_name(63))\n        );        \n    \"#,\n    )\n    .await?;\n\n    let db_name = MySql::db_name(args);\n    do_cleanup(&mut conn, &db_name).await?;\n\n    query(\"insert into _sqlx_test_databases(db_name, test_path) values (?, ?)\")\n        .bind(&db_name)\n        .bind(args.test_path)\n        .execute(&mut *conn)\n        .await?;\n\n    conn.execute(AssertSqlSafe(format!(\"create database {db_name}\")))\n        .await?;\n\n    eprintln!(\"created database {db_name}\");\n\n    Ok(TestContext {\n        pool_opts: PoolOptions::new()\n            // Don't allow a single test to take all the connections.\n            // Most tests shouldn't require more than 5 connections concurrently,\n            // or else they're likely doing too much in one test.\n            .max_connections(5)\n            // Close connections ASAP if left in the idle queue.\n            .idle_timeout(Some(Duration::from_secs(1)))\n            .parent(master_pool.clone()),\n        connect_opts: master_pool\n            .connect_options()\n            .deref()\n            .clone()\n            .database(&db_name),\n        db_name,\n    })\n}\n\nasync fn do_cleanup(conn: &mut MySqlConnection, db_name: &str) -> Result<(), Error> {\n    let delete_db_command = format!(\"drop database if exists {db_name};\");\n    conn.execute(AssertSqlSafe(delete_db_command)).await?;\n    query(\"delete from _sqlx_test_databases where db_name = ?\")\n        .bind(db_name)\n        .execute(&mut *conn)\n        .await?;\n\n    Ok(())\n}\n\nasync fn cleanup_old_dbs(conn: &mut MySqlConnection) -> Result<(), Error> {\n    let res: Result<Vec<u64>, Error> = query_scalar(\"select db_id from _sqlx_test_databases\")\n        .fetch_all(&mut *conn)\n        .await;\n\n    let db_ids = match res {\n        Ok(db_ids) => db_ids,\n        Err(e) => {\n            if let Some(dbe) = e.as_database_error() {\n                match dbe.downcast_ref::<MySqlDatabaseError>().number() {\n                    // Column `db_id` does not exist:\n                    // https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_bad_field_error\n                    //\n                    // The table has already been migrated.\n                    1054 => return Ok(()),\n                    // Table `_sqlx_test_databases` does not exist.\n                    // No cleanup needed.\n                    // https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html#error_er_no_such_table\n                    1146 => return Ok(()),\n                    _ => (),\n                }\n            }\n\n            return Err(e);\n        }\n    };\n\n    // Drop old-style test databases.\n    for id in db_ids {\n        match conn\n            .execute(AssertSqlSafe(format!(\n                \"drop database if exists _sqlx_test_database_{id}\"\n            )))\n            .await\n        {\n            Ok(_deleted) => (),\n            // Assume a database error just means the DB is still in use.\n            Err(Error::Database(dbe)) => {\n                eprintln!(\"could not clean old test database _sqlx_test_database_{id}: {dbe}\");\n            }\n            // Bubble up other errors\n            Err(e) => return Err(e),\n        }\n    }\n\n    conn.execute(\"drop table if exists _sqlx_test_databases\")\n        .await?;\n\n    Ok(())\n}\n\nfn once_lock_try_insert_polyfill<T>(this: &OnceLock<T>, value: T) -> Result<&T, (&T, T)> {\n    let mut value = Some(value);\n    let res = this.get_or_init(|| value.take().unwrap());\n    match value {\n        None => Ok(res),\n        Some(value) => Err((res, value)),\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/transaction.rs",
    "content": "use sqlx_core::sql_str::SqlStr;\n\nuse crate::connection::Waiting;\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::protocol::text::Query;\nuse crate::{MySql, MySqlConnection};\n\npub(crate) use sqlx_core::transaction::*;\n\n/// Implementation of [`TransactionManager`] for MySQL.\npub struct MySqlTransactionManager;\n\nimpl TransactionManager for MySqlTransactionManager {\n    type Database = MySql;\n\n    async fn begin(conn: &mut MySqlConnection, statement: Option<SqlStr>) -> Result<(), Error> {\n        let depth = conn.inner.transaction_depth;\n\n        let statement = match statement {\n            // custom `BEGIN` statements are not allowed if we're already in a transaction\n            // (we need to issue a `SAVEPOINT` instead)\n            Some(_) if depth > 0 => return Err(Error::InvalidSavePointStatement),\n            Some(statement) => statement,\n            None => begin_ansi_transaction_sql(depth),\n        };\n        conn.execute(statement).await?;\n        if !conn.in_transaction() {\n            return Err(Error::BeginFailed);\n        }\n        conn.inner.transaction_depth += 1;\n\n        Ok(())\n    }\n\n    async fn commit(conn: &mut MySqlConnection) -> Result<(), Error> {\n        let depth = conn.inner.transaction_depth;\n\n        if depth > 0 {\n            conn.execute(commit_ansi_transaction_sql(depth)).await?;\n            conn.inner.transaction_depth = depth - 1;\n        }\n\n        Ok(())\n    }\n\n    async fn rollback(conn: &mut MySqlConnection) -> Result<(), Error> {\n        let depth = conn.inner.transaction_depth;\n\n        if depth > 0 {\n            conn.execute(rollback_ansi_transaction_sql(depth)).await?;\n            conn.inner.transaction_depth = depth - 1;\n        }\n\n        Ok(())\n    }\n\n    fn start_rollback(conn: &mut MySqlConnection) {\n        let depth = conn.inner.transaction_depth;\n\n        if depth > 0 {\n            conn.inner.stream.waiting.push_back(Waiting::Result);\n            conn.inner.stream.sequence_id = 0;\n            conn.inner\n                .stream\n                .write_packet(Query(rollback_ansi_transaction_sql(depth).as_str()))\n                .expect(\"BUG: unexpected error queueing ROLLBACK\");\n\n            conn.inner.transaction_depth = depth - 1;\n        }\n    }\n\n    fn get_transaction_depth(conn: &MySqlConnection) -> usize {\n        conn.inner.transaction_depth\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/type_checking.rs",
    "content": "// Type mappings used by the macros and `Debug` impls.\n\n#[allow(unused_imports)]\nuse sqlx_core as sqlx;\n\nuse crate::MySql;\n\nimpl_type_checking!(\n    MySql {\n        u8,\n        u16,\n        u32,\n        u64,\n        i8,\n        i16,\n        i32,\n        i64,\n        f32,\n        f64,\n\n        // ordering is important here as otherwise we might infer strings to be binary\n        // CHAR, VAR_CHAR, TEXT\n        String,\n\n        // BINARY, VAR_BINARY, BLOB\n        Vec<u8>,\n\n        #[cfg(feature = \"json\")]\n        sqlx::types::JsonValue,\n    },\n    ParamChecking::Weak,\n    feature-types: info => info.__type_feature_gate(),\n    // The expansion of the macro automatically applies the correct feature name\n    // and checks `[macros.preferred-crates]`\n    datetime-types: {\n        chrono: {\n            sqlx::types::chrono::NaiveTime,\n\n            sqlx::types::chrono::NaiveDate,\n\n            sqlx::types::chrono::NaiveDateTime,\n\n            sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>,\n        },\n        time: {\n            sqlx::types::time::Time,\n\n            sqlx::types::time::Date,\n\n            sqlx::types::time::PrimitiveDateTime,\n\n            sqlx::types::time::OffsetDateTime,\n        },\n    },\n    numeric-types: {\n        bigdecimal: {\n            sqlx::types::BigDecimal,\n        },\n        rust_decimal: {\n            sqlx::types::Decimal,\n        },\n    },\n);\n"
  },
  {
    "path": "sqlx-mysql/src/type_info.rs",
    "content": "use std::fmt::{self, Display, Formatter};\n\nuse crate::collation::Collation;\nuse crate::protocol::text::{ColumnDefinition, ColumnFlags, ColumnType};\npub(crate) use sqlx_core::type_info::*;\n\n/// Type information for a MySql type.\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct MySqlTypeInfo {\n    pub(crate) r#type: ColumnType,\n    pub(crate) flags: ColumnFlags,\n    pub(crate) collation: Collation,\n\n    // [max_size] for integer types, this is (M) in BIT(M) or TINYINT(M)\n    #[cfg_attr(feature = \"offline\", serde(default))]\n    pub(crate) max_size: Option<u32>,\n}\n\nimpl MySqlTypeInfo {\n    pub(crate) const fn binary(ty: ColumnType) -> Self {\n        Self {\n            r#type: ty,\n            flags: ColumnFlags::BINARY,\n            collation: Collation::BINARY,\n            max_size: None,\n        }\n    }\n\n    #[doc(hidden)]\n    pub const fn __enum() -> Self {\n        // Newer versions of MySQL seem to expect that a parameter binding of `MYSQL_TYPE_ENUM`\n        // means that the value is encoded as an integer.\n        //\n        // For \"strong\" enums inputted as strings, we need to specify this type instead\n        // for wider compatibility. This works on all covered versions of MySQL and MariaDB.\n        //\n        // Annoyingly, MySQL's developer documentation doesn't really explain this anywhere;\n        // this had to be determined experimentally.\n        Self {\n            r#type: ColumnType::String,\n            flags: ColumnFlags::ENUM,\n            collation: Collation::UTF8MB4_GENERAL_CI,\n            max_size: None,\n        }\n    }\n\n    #[doc(hidden)]\n    pub fn __type_feature_gate(&self) -> Option<&'static str> {\n        match self.r#type {\n            ColumnType::Date | ColumnType::Time | ColumnType::Timestamp | ColumnType::Datetime => {\n                Some(\"time\")\n            }\n\n            ColumnType::Json => Some(\"json\"),\n            ColumnType::NewDecimal => Some(\"bigdecimal\"),\n\n            _ => None,\n        }\n    }\n\n    pub(crate) fn from_column(column: &ColumnDefinition) -> Self {\n        Self {\n            r#type: column.r#type,\n            flags: column.flags,\n            collation: column.collation,\n            max_size: Some(column.max_size),\n        }\n    }\n}\n\nimpl Display for MySqlTypeInfo {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.pad(self.name())\n    }\n}\n\nimpl TypeInfo for MySqlTypeInfo {\n    fn is_null(&self) -> bool {\n        matches!(self.r#type, ColumnType::Null)\n    }\n\n    fn name(&self) -> &str {\n        self.r#type.name(self.flags, self.max_size)\n    }\n}\n\nimpl PartialEq<MySqlTypeInfo> for MySqlTypeInfo {\n    fn eq(&self, other: &MySqlTypeInfo) -> bool {\n        if self.r#type != other.r#type {\n            return false;\n        }\n\n        match self.r#type {\n            ColumnType::Tiny\n            | ColumnType::Short\n            | ColumnType::Long\n            | ColumnType::Int24\n            | ColumnType::LongLong => {\n                return self.flags.contains(ColumnFlags::UNSIGNED)\n                    == other.flags.contains(ColumnFlags::UNSIGNED);\n            }\n\n            // for string types, check that our charset matches\n            ColumnType::VarChar\n            | ColumnType::Blob\n            | ColumnType::TinyBlob\n            | ColumnType::MediumBlob\n            | ColumnType::LongBlob\n            | ColumnType::String\n            | ColumnType::VarString\n            | ColumnType::Enum => {\n                return self.flags == other.flags;\n            }\n            _ => {}\n        }\n\n        true\n    }\n}\n\nimpl Eq for MySqlTypeInfo {}\n"
  },
  {
    "path": "sqlx-mysql/src/types/bigdecimal.rs",
    "content": "use bigdecimal::BigDecimal;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::io::MySqlBufMutExt;\nuse crate::protocol::text::ColumnType;\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl Type<MySql> for BigDecimal {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::NewDecimal)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(ty.r#type, ColumnType::Decimal | ColumnType::NewDecimal)\n    }\n}\n\nimpl Encode<'_, MySql> for BigDecimal {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for BigDecimal {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(value.as_str()?.parse()?)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/bool.rs",
    "content": "use crate::collation::Collation;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{\n    protocol::text::{ColumnFlags, ColumnType},\n    MySql, MySqlTypeInfo, MySqlValueRef,\n};\n\nimpl Type<MySql> for bool {\n    fn type_info() -> MySqlTypeInfo {\n        // MySQL has no actual `BOOLEAN` type, the type is an alias of `[UNSIGNED] TINYINT(1)`\n        MySqlTypeInfo {\n            flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,\n            collation: Collation::BINARY,\n            max_size: Some(1),\n            r#type: ColumnType::Tiny,\n        }\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(\n            ty.r#type,\n            ColumnType::Tiny\n                | ColumnType::Short\n                | ColumnType::Long\n                | ColumnType::Int24\n                | ColumnType::LongLong\n                | ColumnType::Bit\n        )\n    }\n}\n\nimpl Encode<'_, MySql> for bool {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        <i8 as Encode<MySql>>::encode(*self as i8, buf)\n    }\n}\n\nimpl Decode<'_, MySql> for bool {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(<i8 as Decode<MySql>>::decode(value)? != 0)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/bytes.rs",
    "content": "use std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::io::MySqlBufMutExt;\nuse crate::protocol::text::ColumnType;\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl Type<MySql> for [u8] {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Blob)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(\n            ty.r#type,\n            ColumnType::VarChar\n                | ColumnType::Blob\n                | ColumnType::TinyBlob\n                | ColumnType::MediumBlob\n                | ColumnType::LongBlob\n                | ColumnType::String\n                | ColumnType::VarString\n                | ColumnType::Enum\n        )\n    }\n}\n\nimpl Encode<'_, MySql> for &'_ [u8] {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_bytes_lenenc(self);\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for &'r [u8] {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        value.as_bytes()\n    }\n}\n\nimpl Type<MySql> for Vec<u8> {\n    fn type_info() -> MySqlTypeInfo {\n        <[u8] as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&[u8] as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for Vec<u8> {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        <&[u8] as Encode<MySql>>::encode(&**self, buf)\n    }\n}\n\nimpl Decode<'_, MySql> for Vec<u8> {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        <&[u8] as Decode<MySql>>::decode(value).map(ToOwned::to_owned)\n    }\n}\n\nforward_encode_impl!(Arc<[u8]>, &[u8], MySql);\nforward_encode_impl!(Rc<[u8]>, &[u8], MySql);\nforward_encode_impl!(Box<[u8]>, &[u8], MySql);\nforward_encode_impl!(Cow<'_, [u8]>, &[u8], MySql);\n"
  },
  {
    "path": "sqlx-mysql/src/types/chrono.rs",
    "content": "use bytes::Buf;\nuse chrono::{\n    DateTime, Datelike, Local, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc,\n};\nuse sqlx_core::database::Database;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::{BoxDynError, UnexpectedNullError};\nuse crate::protocol::text::ColumnType;\nuse crate::type_info::MySqlTypeInfo;\nuse crate::types::{MySqlTime, MySqlTimeSign, Type};\nuse crate::{MySql, MySqlValueFormat, MySqlValueRef};\n\nimpl Type<MySql> for DateTime<Utc> {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Timestamp)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(ty.r#type, ColumnType::Datetime | ColumnType::Timestamp)\n    }\n}\n\n/// Note: assumes the connection's `time_zone` is set to `+00:00` (UTC).\nimpl Encode<'_, MySql> for DateTime<Utc> {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        Encode::<MySql>::encode(self.naive_utc(), buf)\n    }\n}\n\n/// Note: assumes the connection's `time_zone` is set to `+00:00` (UTC).\nimpl<'r> Decode<'r, MySql> for DateTime<Utc> {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        let naive: NaiveDateTime = Decode::<MySql>::decode(value)?;\n\n        Ok(Utc.from_utc_datetime(&naive))\n    }\n}\n\nimpl Type<MySql> for DateTime<Local> {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Timestamp)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(ty.r#type, ColumnType::Datetime | ColumnType::Timestamp)\n    }\n}\n\n/// Note: assumes the connection's `time_zone` is set to `+00:00` (UTC).\nimpl Encode<'_, MySql> for DateTime<Local> {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        Encode::<MySql>::encode(self.naive_utc(), buf)\n    }\n}\n\n/// Note: assumes the connection's `time_zone` is set to `+00:00` (UTC).\nimpl<'r> Decode<'r, MySql> for DateTime<Local> {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(<DateTime<Utc> as Decode<'r, MySql>>::decode(value)?.with_timezone(&Local))\n    }\n}\n\nimpl Type<MySql> for NaiveTime {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTime::type_info()\n    }\n}\n\nimpl Encode<'_, MySql> for NaiveTime {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        let len = naive_time_encoded_len(self);\n        buf.push(len);\n\n        // NaiveTime is not negative\n        buf.push(0);\n\n        // Number of days in the interval; always 0 for time-of-day values.\n        // https://mariadb.com/kb/en/resultset-row/#teimstamp-binary-encoding\n        buf.extend_from_slice(&[0_u8; 4]);\n\n        encode_time(self, len > 8, buf);\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        naive_time_encoded_len(self) as usize + 1 // plus length byte\n    }\n}\n\n/// Decode from a `TIME` value.\n///\n/// ### Errors\n/// Returns an error if the `TIME` value is negative or exceeds `23:59:59.999999`.\nimpl<'r> Decode<'r, MySql> for NaiveTime {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                // Covers most possible failure modes.\n                MySqlTime::decode(value)?.try_into()\n            }\n            // Retaining this parsing for now as it allows us to cross-check our impl.\n            MySqlValueFormat::Text => {\n                let s = value.as_str()?;\n                NaiveTime::parse_from_str(s, \"%H:%M:%S%.f\").map_err(Into::into)\n            }\n        }\n    }\n}\n\nimpl TryFrom<MySqlTime> for NaiveTime {\n    type Error = BoxDynError;\n\n    fn try_from(time: MySqlTime) -> Result<Self, Self::Error> {\n        NaiveTime::from_hms_micro_opt(\n            time.hours(),\n            time.minutes() as u32,\n            time.seconds() as u32,\n            time.microseconds(),\n        )\n        .ok_or_else(|| format!(\"Cannot convert `MySqlTime` value to `NaiveTime`: {time}\").into())\n    }\n}\n\nimpl From<MySqlTime> for chrono::TimeDelta {\n    fn from(time: MySqlTime) -> Self {\n        chrono::TimeDelta::new(time.whole_seconds_signed(), time.subsec_nanos())\n            .expect(\"BUG: chrono::TimeDelta should have a greater range than MySqlTime\")\n    }\n}\n\nimpl TryFrom<chrono::TimeDelta> for MySqlTime {\n    type Error = BoxDynError;\n\n    fn try_from(value: chrono::TimeDelta) -> Result<Self, Self::Error> {\n        let sign = if value < chrono::TimeDelta::zero() {\n            MySqlTimeSign::Negative\n        } else {\n            MySqlTimeSign::Positive\n        };\n\n        Ok(\n            // `std::time::Duration` has a greater positive range than `TimeDelta`\n            // which makes it a great intermediate if you ignore the sign.\n            MySqlTime::try_from(value.abs().to_std()?)?.with_sign(sign),\n        )\n    }\n}\n\nimpl Type<MySql> for chrono::TimeDelta {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTime::type_info()\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for chrono::TimeDelta {\n    fn decode(value: <MySql as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(MySqlTime::decode(value)?.into())\n    }\n}\n\nimpl Type<MySql> for NaiveDate {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Date)\n    }\n}\n\nimpl Encode<'_, MySql> for NaiveDate {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.push(4);\n\n        encode_date(self, buf)?;\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        5\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for NaiveDate {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                let buf = value.as_bytes()?;\n\n                // Row decoding should have left the length prefix.\n                if buf.is_empty() {\n                    return Err(\"empty buffer\".into());\n                }\n\n                decode_date(&buf[1..])?.ok_or_else(|| UnexpectedNullError.into())\n            }\n\n            MySqlValueFormat::Text => {\n                let s = value.as_str()?;\n                NaiveDate::parse_from_str(s, \"%Y-%m-%d\").map_err(Into::into)\n            }\n        }\n    }\n}\n\nimpl Type<MySql> for NaiveDateTime {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Datetime)\n    }\n}\n\nimpl Encode<'_, MySql> for NaiveDateTime {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        let len = naive_dt_encoded_len(self);\n        buf.push(len);\n\n        encode_date(&self.date(), buf)?;\n\n        if len > 4 {\n            encode_time(&self.time(), len > 7, buf);\n        }\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        naive_dt_encoded_len(self) as usize + 1 // plus length byte\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for NaiveDateTime {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                let buf = value.as_bytes()?;\n\n                if buf.is_empty() {\n                    return Err(\"empty buffer\".into());\n                }\n\n                let len = buf[0];\n                let date = decode_date(&buf[1..])?.ok_or(UnexpectedNullError)?;\n\n                let dt = if len > 4 {\n                    date.and_time(decode_time(len - 4, &buf[5..])?)\n                } else {\n                    date.and_hms_opt(0, 0, 0)\n                        .expect(\"expected `NaiveDate::and_hms_opt(0, 0, 0)` to be valid\")\n                };\n\n                Ok(dt)\n            }\n\n            MySqlValueFormat::Text => {\n                let s = value.as_str()?;\n                NaiveDateTime::parse_from_str(s, \"%Y-%m-%d %H:%M:%S%.f\").map_err(Into::into)\n            }\n        }\n    }\n}\n\nfn encode_date(date: &NaiveDate, buf: &mut Vec<u8>) -> Result<(), BoxDynError> {\n    // MySQL supports years 1000 - 9999\n    let year = u16::try_from(date.year())\n        .map_err(|_| format!(\"NaiveDateTime out of range for Mysql: {date}\"))?;\n\n    buf.extend_from_slice(&year.to_le_bytes());\n\n    // `NaiveDate` guarantees the ranges of these values\n    #[allow(clippy::cast_possible_truncation)]\n    {\n        buf.push(date.month() as u8);\n        buf.push(date.day() as u8);\n    }\n\n    Ok(())\n}\n\nfn decode_date(mut buf: &[u8]) -> Result<Option<NaiveDate>, BoxDynError> {\n    match buf.len() {\n        // MySQL specifies that if there are no bytes, this is all zeros\n        0 => Ok(None),\n        4.. => {\n            let year = buf.get_u16_le() as i32;\n            let month = buf[0] as u32;\n            let day = buf[1] as u32;\n\n            let date = NaiveDate::from_ymd_opt(year, month, day)\n                .ok_or_else(|| format!(\"server returned invalid date: {year}/{month}/{day}\"))?;\n\n            Ok(Some(date))\n        }\n        len => Err(format!(\"expected at least 4 bytes for date, got {len}\").into()),\n    }\n}\n\nfn encode_time(time: &NaiveTime, include_micros: bool, buf: &mut Vec<u8>) {\n    // `NaiveTime` API guarantees the ranges of these values\n    #[allow(clippy::cast_possible_truncation)]\n    {\n        buf.push(time.hour() as u8);\n        buf.push(time.minute() as u8);\n        buf.push(time.second() as u8);\n    }\n\n    if include_micros {\n        buf.extend((time.nanosecond() / 1000).to_le_bytes());\n    }\n}\n\nfn decode_time(len: u8, mut buf: &[u8]) -> Result<NaiveTime, BoxDynError> {\n    let hour = buf.get_u8();\n    let minute = buf.get_u8();\n    let seconds = buf.get_u8();\n\n    let micros = if len > 3 {\n        // microseconds : int<EOF>\n        buf.get_uint_le(buf.len())\n    } else {\n        0\n    };\n\n    let micros = u32::try_from(micros)\n        .map_err(|_| format!(\"server returned microseconds out of range: {micros}\"))?;\n\n    NaiveTime::from_hms_micro_opt(hour as u32, minute as u32, seconds as u32, micros)\n        .ok_or_else(|| format!(\"server returned invalid time: {hour:02}:{minute:02}:{seconds:02}; micros: {micros}\").into())\n}\n\n#[inline(always)]\nfn naive_dt_encoded_len(time: &NaiveDateTime) -> u8 {\n    // to save space the packet can be compressed:\n    match (\n        time.hour(),\n        time.minute(),\n        time.second(),\n        #[allow(deprecated)]\n        time.timestamp_subsec_nanos(),\n    ) {\n        // if hour, minutes, seconds and micro_seconds are all 0,\n        // length is 4 and no other field is sent\n        (0, 0, 0, 0) => 4,\n\n        // if micro_seconds is 0, length is 7\n        // and micro_seconds is not sent\n        (_, _, _, 0) => 7,\n\n        // otherwise length is 11\n        (_, _, _, _) => 11,\n    }\n}\n\n#[inline(always)]\nfn naive_time_encoded_len(time: &NaiveTime) -> u8 {\n    if time.nanosecond() == 0 {\n        // if micro_seconds is 0, length is 8 and micro_seconds is not sent\n        8\n    } else {\n        // otherwise length is 12\n        12\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/float.rs",
    "content": "use byteorder::{ByteOrder, LittleEndian};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::protocol::text::ColumnType;\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueFormat, MySqlValueRef};\n\nfn real_compatible(ty: &MySqlTypeInfo) -> bool {\n    // NOTE: `DECIMAL` is explicitly excluded because floating-point numbers have different semantics.\n    matches!(ty.r#type, ColumnType::Float | ColumnType::Double)\n}\n\nimpl Type<MySql> for f32 {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Float)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        real_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for f64 {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Double)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        real_compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for f32 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for f64 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for f32 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            MySqlValueFormat::Binary => {\n                let buf = value.as_bytes()?;\n\n                match buf.len() {\n                    // These functions panic if `buf` is not exactly the right size.\n                    4 => LittleEndian::read_f32(buf),\n                    // MySQL can return 8-byte DOUBLE values for a FLOAT\n                    // We take and truncate to f32 as that's the same behavior as *in* MySQL,\n                    #[allow(clippy::cast_possible_truncation)]\n                    8 => LittleEndian::read_f64(buf) as f32,\n                    other => {\n                        // Users may try to decode a DECIMAL as floating point;\n                        // inform them why that's a bad idea.\n                        return Err(format!(\n                            \"expected a FLOAT as 4 or 8 bytes, got {other} bytes; \\\n                             note that decoding DECIMAL as `f32` is not supported \\\n                             due to differing semantics\"\n                        )\n                        .into());\n                    }\n                }\n            }\n\n            MySqlValueFormat::Text => value.as_str()?.parse()?,\n        })\n    }\n}\n\nimpl Decode<'_, MySql> for f64 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            MySqlValueFormat::Binary => {\n                let buf = value.as_bytes()?;\n\n                // The `read_*` functions panic if `buf` is not exactly the right size.\n                match buf.len() {\n                    // Allow implicit widening here\n                    4 => LittleEndian::read_f32(buf) as f64,\n                    8 => LittleEndian::read_f64(buf),\n                    other => {\n                        // Users may try to decode a DECIMAL as floating point;\n                        // inform them why that's a bad idea.\n                        return Err(format!(\n                            \"expected a DOUBLE as 4 or 8 bytes, got {other} bytes; \\\n                             note that decoding DECIMAL as `f64` is not supported \\\n                             due to differing semantics\"\n                        )\n                        .into());\n                    }\n                }\n            }\n            MySqlValueFormat::Text => value.as_str()?.parse()?,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/inet.rs",
    "content": "use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::io::MySqlBufMutExt;\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl Type<MySql> for Ipv4Addr {\n    fn type_info() -> MySqlTypeInfo {\n        <&str as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&str as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for Ipv4Addr {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for Ipv4Addr {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        // delegate to the &str type to decode from MySQL\n        let text = <&str as Decode<MySql>>::decode(value)?;\n\n        // parse a Ipv4Addr from the text\n        text.parse().map_err(Into::into)\n    }\n}\n\nimpl Type<MySql> for Ipv6Addr {\n    fn type_info() -> MySqlTypeInfo {\n        <&str as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&str as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for Ipv6Addr {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for Ipv6Addr {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        // delegate to the &str type to decode from MySQL\n        let text = <&str as Decode<MySql>>::decode(value)?;\n\n        // parse a Ipv6Addr from the text\n        text.parse().map_err(Into::into)\n    }\n}\n\nimpl Type<MySql> for IpAddr {\n    fn type_info() -> MySqlTypeInfo {\n        <&str as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&str as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for IpAddr {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for IpAddr {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        // delegate to the &str type to decode from MySQL\n        let text = <&str as Decode<MySql>>::decode(value)?;\n\n        // parse a IpAddr from the text\n        text.parse().map_err(Into::into)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/int.rs",
    "content": "use byteorder::{ByteOrder, LittleEndian};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::protocol::text::{ColumnFlags, ColumnType};\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueFormat, MySqlValueRef};\n\nfn int_compatible(ty: &MySqlTypeInfo) -> bool {\n    matches!(\n        ty.r#type,\n        ColumnType::Tiny\n            | ColumnType::Short\n            | ColumnType::Long\n            | ColumnType::Int24\n            | ColumnType::LongLong\n    ) && !ty.flags.contains(ColumnFlags::UNSIGNED)\n}\n\nimpl Type<MySql> for i8 {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Tiny)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        int_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for i16 {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Short)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        int_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for i32 {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Long)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        int_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for i64 {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::LongLong)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        int_compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for i8 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for i16 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for i32 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for i64 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nfn int_decode(value: MySqlValueRef<'_>) -> Result<i64, BoxDynError> {\n    Ok(match value.format() {\n        MySqlValueFormat::Text => value.as_str()?.parse()?,\n        MySqlValueFormat::Binary => {\n            let buf = value.as_bytes()?;\n\n            // Check conditions that could cause `read_int()` to panic.\n            if buf.is_empty() {\n                return Err(\"empty buffer\".into());\n            }\n\n            if buf.len() > 8 {\n                return Err(format!(\n                    \"expected no more than 8 bytes for integer value, got {}\",\n                    buf.len()\n                )\n                .into());\n            }\n\n            LittleEndian::read_int(buf, buf.len())\n        }\n    })\n}\n\nimpl Decode<'_, MySql> for i8 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Decode<'_, MySql> for i16 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Decode<'_, MySql> for i32 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Decode<'_, MySql> for i64 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/json.rs",
    "content": "use serde::{Deserialize, Serialize};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::protocol::text::ColumnType;\nuse crate::types::{Json, Type};\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl<T> Type<MySql> for Json<T> {\n    fn type_info() -> MySqlTypeInfo {\n        // MySql uses the `CHAR` type to pass JSON data from and to the client\n        // NOTE: This is forwards-compatible with MySQL v8+ as CHAR is a common transmission format\n        //       and has nothing to do with the native storage ability of MySQL v8+\n        MySqlTypeInfo::binary(ColumnType::String)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        ty.r#type == ColumnType::Json\n            || <&str as Type<MySql>>::compatible(ty)\n            || <&[u8] as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl<T> Encode<'_, MySql> for Json<T>\nwhere\n    T: Serialize,\n{\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        // Encode JSON as a length-prefixed string.\n        //\n        // The previous implementation encoded into an intermediate buffer to get the final length.\n        // This is because the length prefix for the string is itself length-encoded, so we have\n        // to know the length first before we can start encoding in the buffer... or do we?\n        //\n        // The docs suggest that the integer length-encoding doesn't actually enforce a range on\n        // the value itself as long as it fits in the chosen encoding, so why not just choose\n        // the full length encoding to begin with? Then we can just reserve the space up-front\n        // and encode directly into the buffer.\n        //\n        // If someone is storing a JSON value it's likely large enough that the overhead of using\n        // the full-length integer encoding doesn't really matter. And if it's so large it overflows\n        // a `u64` then the process is likely to run OOM during the encoding process first anyway.\n\n        let lenenc_start = buf.len();\n\n        buf.extend_from_slice(&[0u8; 9]);\n\n        let encode_start = buf.len();\n        self.encode_to(buf)?;\n        let encoded_len = (buf.len() - encode_start) as u64;\n\n        // This prefix indicates that the following 8 bytes are a little-endian integer.\n        buf[lenenc_start] = 0xFE;\n        buf[lenenc_start + 1..][..8].copy_from_slice(&encoded_len.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r, T> Decode<'r, MySql> for Json<T>\nwhere\n    T: 'r + Deserialize<'r>,\n{\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        Json::decode_from_string(value.as_str()?)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/mod.rs",
    "content": "//! Conversions between Rust and **MySQL/MariaDB** types.\n//!\n//! # Types\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bool`                                | TINYINT(1), BOOLEAN, BOOL (see below)                |\n//! | `i8`                                  | TINYINT                                              |\n//! | `i16`                                 | SMALLINT                                             |\n//! | `i32`                                 | INT                                                  |\n//! | `i64`                                 | BIGINT                                               |\n//! | `u8`                                  | TINYINT UNSIGNED                                     |\n//! | `u16`                                 | SMALLINT UNSIGNED                                    |\n//! | `u32`                                 | INT UNSIGNED                                         |\n//! | `u64`                                 | BIGINT UNSIGNED                                      |\n//! | `f32`                                 | FLOAT                                                |\n//! | `f64`                                 | DOUBLE                                               |\n//! | `&str`, [`String`]                    | VARCHAR, CHAR, TEXT                                  |\n//! | `&[u8]`, `Vec<u8>`                    | VARBINARY, BINARY, BLOB                              |\n//! | `IpAddr`                              | VARCHAR, TEXT                                        |\n//! | `Ipv4Addr`                            | INET4 (MariaDB-only), VARCHAR, TEXT                  |\n//! | `Ipv6Addr`                            | INET6 (MariaDB-only), VARCHAR, TEXT                  |\n//! | [`MySqlTime`]                         | TIME (encode and decode full range)                  |\n//! | [`Duration`][std::time::Duration]     | TIME (for decoding positive values only)             |\n//!\n//! ##### Note: `BOOLEAN`/`BOOL` Type\n//! MySQL and MariaDB treat `BOOLEAN` as an alias of the `TINYINT` type:\n//!\n//! * [Using Data Types from Other Database Engines (MySQL)](https://dev.mysql.com/doc/refman/8.0/en/other-vendor-data-types.html)\n//! * [BOOLEAN (MariaDB)](https://mariadb.com/kb/en/boolean/)\n//!\n//! For the most part, you can simply use the Rust type `bool` when encoding or decoding a value\n//! using the dynamic query interface, or passing a boolean as a parameter to the query macros\n//! (`query!()` _et al._).\n//!\n//! However, because the MySQL wire protocol does not distinguish between `TINYINT` and `BOOLEAN`,\n//! the query macros cannot know that a `TINYINT` column is semantically a boolean.\n//! By default, they will map a `TINYINT` column as `i8` instead, as that is the safer assumption.\n//!\n//! Thus, you must use the type override syntax in the query to tell the macros you are expecting\n//! a `bool` column. See the docs for `query!()` and `query_as!()` for details on this syntax.\n//!\n//! ### NOTE: MySQL's `TIME` type is signed\n//! MySQL's `TIME` type can be used as either a time-of-day value, or a signed interval.\n//! Thus, it may take on negative values.\n//!\n//! Decoding a [`std::time::Duration`] returns an error if the `TIME` value is negative.\n//!\n//! ### [`chrono`](https://crates.io/crates/chrono)\n//!\n//! Requires the `chrono` Cargo feature flag.\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `chrono::DateTime<Utc>`               | TIMESTAMP                                            |\n//! | `chrono::DateTime<Local>`             | TIMESTAMP                                            |\n//! | `chrono::NaiveDateTime`               | DATETIME                                             |\n//! | `chrono::NaiveDate`                   | DATE                                                 |\n//! | `chrono::NaiveTime`                   | TIME (time-of-day only)                              |\n//! | `chrono::TimeDelta`                   | TIME (decodes full range; see note for encoding)     |\n//!\n//! ### NOTE: MySQL's `TIME` type is dual-purpose\n//! MySQL's `TIME` type can be used as either a time-of-day value, or an interval.\n//! However, `chrono::NaiveTime` is designed only to represent a time-of-day.\n//!\n//! Decoding a `TIME` value as `chrono::NaiveTime` will return an error if the value is out of range.\n//!\n//! The [`MySqlTime`] type supports the full range and it also implements `TryInto<chrono::NaiveTime>`.\n//!\n//! Decoding a `chrono::TimeDelta` also supports the full range.\n//!\n//! To encode a `chrono::TimeDelta`, convert it to [`MySqlTime`] first using `TryFrom`/`TryInto`.\n//!\n//! ### [`time`](https://crates.io/crates/time)\n//!\n//! Requires the `time` Cargo feature flag.\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `time::PrimitiveDateTime`             | DATETIME                                             |\n//! | `time::OffsetDateTime`                | TIMESTAMP                                            |\n//! | `time::Date`                          | DATE                                                 |\n//! | `time::Time`                          | TIME (time-of-day only)                              |\n//! | `time::Duration`                      | TIME (decodes full range; see note for encoding)     |\n//!\n//! ### NOTE: MySQL's `TIME` type is dual-purpose\n//! MySQL's `TIME` type can be used as either a time-of-day value, or an interval.\n//! However, `time::Time` is designed only to represent a time-of-day.\n//!\n//! Decoding a `TIME` value as `time::Time` will return an error if the value is out of range.\n//!\n//! The [`MySqlTime`] type supports the full range, and it also implements `TryInto<time::Time>`.\n//!\n//! Decoding a `time::Duration` also supports the full range.\n//!\n//! To encode a `time::Duration`, convert it to [`MySqlTime`] first using `TryFrom`/`TryInto`.\n//!\n//! ### [`bigdecimal`](https://crates.io/crates/bigdecimal)\n//! Requires the `bigdecimal` Cargo feature flag.\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bigdecimal::BigDecimal`              | DECIMAL                                              |\n//!\n//! ### [`decimal`](https://crates.io/crates/rust_decimal)\n//! Requires the `decimal` Cargo feature flag.\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `rust_decimal::Decimal`               | DECIMAL                                              |\n//!\n//! ### [`uuid`](https://crates.io/crates/uuid)\n//!\n//! Requires the `uuid` Cargo feature flag.\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `uuid::Uuid`                          | BINARY(16) (see note)                                |\n//! | `uuid::fmt::Hyphenated`               | CHAR(36), VARCHAR, TEXT, UUID (MariaDB-only)         |\n//! | `uuid::fmt::Simple`                   | CHAR(32), VARCHAR, TEXT                              |\n//!\n//! #### Note: `Uuid` uses binary format\n//!\n//! MySQL does not have a native datatype for UUIDs.\n//! The `UUID()` function returns a 36-character `TEXT` value,\n//! which encourages storing UUIDs as text.\n//!\n//! MariaDB's `UUID` type stores and retrieves as text, though it has a better representation\n//! for index sorting (see [MariaDB manual: UUID data-type][mariadb-uuid] for details).\n//!\n//! As an opinionated library, SQLx chose to map `uuid::Uuid` to/from binary format by default\n//! (16 bytes, the raw value of a UUID; SQL type `BINARY(16)`).\n//! This saves 20 bytes over the text format for each value.\n//!\n//! The `impl Decode<MySql> for Uuid` does not support the text format, and will return an error.\n//!\n//! If you want to use the text format compatible with the `UUID()` function,\n//! use [`uuid::fmt::Hyphenated`][::uuid::fmt::Hyphenated] in the place of `Uuid`.\n//!\n//! The MySQL official blog has an article showing how to support both binary and text format UUIDs\n//! by storing the binary and adding a generated column for the text format, though this is rather\n//! verbose and fiddly: <https://dev.mysql.com/blog-archive/storing-uuid-values-in-mysql-tables/>\n//!\n//! [mariadb-uuid]: https://mariadb.com/kb/en/uuid-data-type/\n//!\n//! ### [`json`](https://crates.io/crates/serde_json)\n//!\n//! Requires the `json` Cargo feature flag.\n//!\n//! | Rust type                             | MySQL/MariaDB type(s)                                |\n//! |---------------------------------------|------------------------------------------------------|\n//! | [`Json<T>`]                           | JSON                                                 |\n//! | `serde_json::JsonValue`               | JSON                                                 |\n//! | `&serde_json::value::RawValue`        | JSON                                                 |\n//!\n//! # Nullable\n//!\n//! In addition, `Option<T>` is supported where `T` implements `Type`. An `Option<T>` represents\n//! a potentially `NULL` value from MySQL/MariaDB.\n\npub(crate) use sqlx_core::types::*;\n\npub use mysql_time::{MySqlTime, MySqlTimeError, MySqlTimeSign};\n\nmod bool;\nmod bytes;\nmod float;\nmod inet;\nmod int;\nmod mysql_time;\nmod str;\nmod text;\nmod uint;\n\n#[cfg(feature = \"json\")]\nmod json;\n\n#[cfg(feature = \"bigdecimal\")]\nmod bigdecimal;\n\n#[cfg(feature = \"rust_decimal\")]\nmod rust_decimal;\n\n#[cfg(feature = \"chrono\")]\nmod chrono;\n\n#[cfg(feature = \"time\")]\nmod time;\n\n#[cfg(feature = \"uuid\")]\nmod uuid;\n"
  },
  {
    "path": "sqlx-mysql/src/types/mysql_time.rs",
    "content": "//! The [`MysqlTime`] type.\n\nuse crate::protocol::text::ColumnType;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueFormat};\nuse bytes::{Buf, BufMut};\nuse sqlx_core::database::Database;\nuse sqlx_core::decode::Decode;\nuse sqlx_core::encode::{Encode, IsNull};\nuse sqlx_core::error::BoxDynError;\nuse sqlx_core::types::Type;\nuse std::cmp::Ordering;\nuse std::fmt::{Debug, Display, Formatter, Write};\nuse std::time::Duration;\n\n// Similar to `PgInterval`\n/// Container for a MySQL `TIME` value, which may be an interval or a time-of-day.\n///\n/// Allowed range is `-838:59:59.0` to `838:59:59.0`.\n///\n/// If this value is used for a time-of-day, the range should be `00:00:00.0` to `23:59:59.999999`.\n/// You can use [`Self::is_valid_time_of_day()`] to check this easily.\n///\n/// * [MySQL Manual 13.2.3: The TIME Type](https://dev.mysql.com/doc/refman/8.3/en/time.html)\n/// * [MariaDB Manual: TIME](https://mariadb.com/kb/en/time/)\n#[derive(Debug, Copy, Clone, Eq, PartialEq)]\npub struct MySqlTime {\n    pub(crate) sign: MySqlTimeSign,\n    pub(crate) magnitude: TimeMagnitude,\n}\n\n// By using a subcontainer for the actual time magnitude,\n// we can still use a derived `Ord` implementation and just flip the comparison for negative values.\n#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]\npub(crate) struct TimeMagnitude {\n    pub(crate) hours: u32,\n    pub(crate) minutes: u8,\n    pub(crate) seconds: u8,\n    pub(crate) microseconds: u32,\n}\n\nconst MAGNITUDE_ZERO: TimeMagnitude = TimeMagnitude {\n    hours: 0,\n    minutes: 0,\n    seconds: 0,\n    microseconds: 0,\n};\n\n/// Maximum magnitude (positive or negative).\nconst MAGNITUDE_MAX: TimeMagnitude = TimeMagnitude {\n    hours: MySqlTime::HOURS_MAX,\n    minutes: 59,\n    seconds: 59,\n    // Surprisingly this is not 999_999 which is why `MySqlTimeError::SubsecondExcess`.\n    microseconds: 0,\n};\n\n/// The sign for a [`MySqlTime`] type.\n#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]\npub enum MySqlTimeSign {\n    // The protocol actually specifies negative as 1 and positive as 0,\n    // but by specifying variants this way we can derive `Ord` and it works as expected.\n    /// The interval is negative (invalid for time-of-day values).\n    Negative,\n    /// The interval is positive, or represents a time-of-day.\n    Positive,\n}\n\n/// Errors returned by [`MySqlTime::new()`].\n#[derive(Debug, thiserror::Error)]\npub enum MySqlTimeError {\n    /// A field of [`MySqlTime`] exceeded its max range.\n    #[error(\"`MySqlTime` field `{field}` cannot exceed {max}, got {value}\")]\n    FieldRange {\n        field: &'static str,\n        max: u32,\n        value: u64,\n    },\n    /// Error returned for time magnitudes (positive or negative) between `838:59:59.0` and `839:00:00.0`.\n    ///\n    /// Other range errors should be covered by [`Self::FieldRange`] for the `hours` field.\n    ///\n    /// For applications which can tolerate rounding, a valid truncated value is provided.\n    #[error(\n        \"`MySqlTime` cannot exceed +/-838:59:59.000000; got {sign}838:59:59.{microseconds:06}\"\n    )]\n    SubsecondExcess {\n        /// The sign of the magnitude.\n        sign: MySqlTimeSign,\n        /// The number of microseconds over the maximum.\n        microseconds: u32,\n        /// The truncated value,\n        /// either [`MySqlTime::MIN`] if negative or [`MySqlTime::MAX`] if positive.\n        truncated: MySqlTime,\n    },\n    /// MySQL coerces `-00:00:00` to `00:00:00` but this API considers that an error.\n    ///\n    /// For applications which can tolerate coercion, you can convert this error to [`MySqlTime::ZERO`].\n    #[error(\"attempted to construct a `MySqlTime` value of negative zero\")]\n    NegativeZero,\n}\n\nimpl MySqlTime {\n    /// The `MySqlTime` value corresponding to `TIME '0:00:00.0'` (zero).\n    pub const ZERO: Self = MySqlTime {\n        sign: MySqlTimeSign::Positive,\n        magnitude: MAGNITUDE_ZERO,\n    };\n\n    /// The `MySqlTime` value corresponding to `TIME '838:59:59.0'` (max value).\n    pub const MAX: Self = MySqlTime {\n        sign: MySqlTimeSign::Positive,\n        magnitude: MAGNITUDE_MAX,\n    };\n\n    /// The `MySqlTime` value corresponding to `TIME '-838:59:59.0'` (min value).\n    pub const MIN: Self = MySqlTime {\n        sign: MySqlTimeSign::Negative,\n        // Same magnitude, opposite sign.\n        magnitude: MAGNITUDE_MAX,\n    };\n\n    // The maximums for the other values are self-evident, but not necessarily this one.\n    pub(crate) const HOURS_MAX: u32 = 838;\n\n    /// Construct a [`MySqlTime`] that is valid for use as a `TIME` value.\n    ///\n    /// ### Errors\n    /// * [`MySqlTimeError::NegativeZero`] if all fields are 0 but `sign` is [`MySqlTimeSign::Negative`].\n    /// * [`MySqlTimeError::FieldRange`] if any field is out of range:\n    ///     * `hours > 838`\n    ///     * `minutes > 59`\n    ///     * `seconds > 59`\n    ///     * `microseconds > 999_999`\n    /// * [`MySqlTimeError::SubsecondExcess`] if the magnitude is less than one second over the maximum.\n    ///     * Durations 839 hours or greater are covered by `FieldRange`.\n    pub fn new(\n        sign: MySqlTimeSign,\n        hours: u32,\n        minutes: u8,\n        seconds: u8,\n        microseconds: u32,\n    ) -> Result<Self, MySqlTimeError> {\n        macro_rules! check_fields {\n            ($($name:ident: $max:expr),+ $(,)?) => {\n                $(\n                    if $name > $max {\n                        return Err(MySqlTimeError::FieldRange {\n                            field: stringify!($name),\n                            max: $max as u32,\n                            value: $name as u64\n                        })\n                    }\n                )+\n            }\n        }\n\n        check_fields!(\n            hours: Self::HOURS_MAX,\n            minutes: 59,\n            seconds: 59,\n            microseconds: 999_999\n        );\n\n        let values = TimeMagnitude {\n            hours,\n            minutes,\n            seconds,\n            microseconds,\n        };\n\n        if sign.is_negative() && values == MAGNITUDE_ZERO {\n            return Err(MySqlTimeError::NegativeZero);\n        }\n\n        // This is only `true` if less than 1 second over the maximum magnitude\n        if values > MAGNITUDE_MAX {\n            return Err(MySqlTimeError::SubsecondExcess {\n                sign,\n                microseconds,\n                truncated: if sign.is_positive() {\n                    Self::MAX\n                } else {\n                    Self::MIN\n                },\n            });\n        }\n\n        Ok(Self {\n            sign,\n            magnitude: values,\n        })\n    }\n\n    /// Update the `sign` of this value.\n    pub fn with_sign(self, sign: MySqlTimeSign) -> Self {\n        Self { sign, ..self }\n    }\n\n    /// Return the sign (positive or negative) for this TIME value.\n    pub fn sign(&self) -> MySqlTimeSign {\n        self.sign\n    }\n\n    /// Returns `true` if `self` is zero (equal to [`Self::ZERO`]).\n    pub fn is_zero(&self) -> bool {\n        self == &Self::ZERO\n    }\n\n    /// Returns `true` if `self` is positive or zero, `false` if negative.\n    pub fn is_positive(&self) -> bool {\n        self.sign.is_positive()\n    }\n\n    /// Returns `true` if `self` is negative, `false` if positive or zero.\n    pub fn is_negative(&self) -> bool {\n        self.sign.is_positive()\n    }\n\n    /// Returns `true` if this interval is a valid time-of-day.\n    ///\n    /// If `true`, the sign is positive and `hours` is not greater than 23.\n    pub fn is_valid_time_of_day(&self) -> bool {\n        self.sign.is_positive() && self.hours() < 24\n    }\n\n    /// Get the total number of hours in this interval, from 0 to 838.\n    ///\n    /// If this value represents a time-of-day, the range is 0 to 23.\n    pub fn hours(&self) -> u32 {\n        self.magnitude.hours\n    }\n\n    /// Get the number of minutes in this interval, from 0 to 59.\n    pub fn minutes(&self) -> u8 {\n        self.magnitude.minutes\n    }\n\n    /// Get the number of seconds in this interval, from 0 to 59.\n    pub fn seconds(&self) -> u8 {\n        self.magnitude.seconds\n    }\n\n    /// Get the number of seconds in this interval, from 0 to 999,999.\n    pub fn microseconds(&self) -> u32 {\n        self.magnitude.microseconds\n    }\n\n    /// Convert this TIME value to a [`std::time::Duration`].\n    ///\n    /// Returns `None` if this value is negative (cannot be represented).\n    pub fn to_duration(&self) -> Option<Duration> {\n        self.is_positive()\n            .then(|| Duration::new(self.whole_seconds() as u64, self.subsec_nanos()))\n    }\n\n    /// Get the whole number of seconds (`seconds + (minutes * 60) + (hours * 3600)`) in this time.\n    ///\n    /// Sign is ignored.\n    pub(crate) fn whole_seconds(&self) -> u32 {\n        // If `hours` does not exceed 838 then this cannot overflow.\n        self.hours() * 3600 + self.minutes() as u32 * 60 + self.seconds() as u32\n    }\n\n    #[cfg_attr(not(any(feature = \"time\", feature = \"chrono\")), allow(dead_code))]\n    pub(crate) fn whole_seconds_signed(&self) -> i64 {\n        self.whole_seconds() as i64 * self.sign.signum() as i64\n    }\n\n    pub(crate) fn subsec_nanos(&self) -> u32 {\n        self.microseconds() * 1000\n    }\n\n    fn encoded_len(&self) -> u8 {\n        if self.is_zero() {\n            0\n        } else if self.microseconds() == 0 {\n            8\n        } else {\n            12\n        }\n    }\n}\n\nimpl PartialOrd<MySqlTime> for MySqlTime {\n    fn partial_cmp(&self, other: &MySqlTime) -> Option<Ordering> {\n        Some(self.cmp(other))\n    }\n}\n\nimpl Ord for MySqlTime {\n    fn cmp(&self, other: &Self) -> Ordering {\n        // If the sides have different signs, we just need to compare those.\n        if self.sign != other.sign {\n            return self.sign.cmp(&other.sign);\n        }\n\n        // We've checked that both sides have the same sign\n        match self.sign {\n            MySqlTimeSign::Positive => self.magnitude.cmp(&other.magnitude),\n            // Reverse the comparison for negative values (smaller negative magnitude = greater)\n            MySqlTimeSign::Negative => other.magnitude.cmp(&self.magnitude),\n        }\n    }\n}\n\nimpl Display for MySqlTime {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        let TimeMagnitude {\n            hours,\n            minutes,\n            seconds,\n            microseconds,\n        } = self.magnitude;\n\n        // Obeys the `+` flag.\n        Display::fmt(&self.sign(), f)?;\n\n        write!(f, \"{hours}:{minutes:02}:{seconds:02}\")?;\n\n        // Write microseconds if not zero or a nonzero precision was explicitly requested.\n        if f.precision().map_or(microseconds != 0, |it| it != 0) {\n            f.write_char('.')?;\n\n            let mut remaining_precision = f.precision();\n            let mut remainder = microseconds;\n            let mut power_of_10 = 10u32.pow(5);\n\n            // Write digits from most-significant to least, up to the requested precision.\n            while remainder > 0 && remaining_precision != Some(0) {\n                let digit = remainder / power_of_10;\n                // 1 % 1 = 0\n                remainder %= power_of_10;\n                power_of_10 /= 10;\n\n                write!(f, \"{digit}\")?;\n\n                if let Some(remaining_precision) = &mut remaining_precision {\n                    *remaining_precision = remaining_precision.saturating_sub(1);\n                }\n            }\n\n            // If any requested precision remains, pad with zeroes.\n            if let Some(precision) = remaining_precision.filter(|it| *it != 0) {\n                write!(f, \"{:0precision$}\", 0)?;\n            }\n        }\n\n        Ok(())\n    }\n}\n\nimpl Type<MySql> for MySqlTime {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Time)\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for MySqlTime {\n    fn decode(value: <MySql as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                let mut buf = value.as_bytes()?;\n\n                // Row decoding should have left the length byte on the front.\n                if buf.is_empty() {\n                    return Err(\"empty buffer\".into());\n                }\n\n                let length = buf.get_u8();\n\n                // MySQL specifies that if all fields are 0 then the length is 0 and no further data is sent\n                // https://dev.mysql.com/doc/internals/en/binary-protocol-value.html\n                if length == 0 {\n                    return Ok(Self::ZERO);\n                }\n\n                if !matches!(buf.len(), 8 | 12) {\n                    return Err(format!(\n                        \"expected 8 or 12 bytes for TIME value, got {}\",\n                        buf.len()\n                    )\n                    .into());\n                }\n\n                let sign = MySqlTimeSign::from_byte(buf.get_u8())?;\n                // The wire protocol includes days but the text format doesn't. Isn't that crazy?\n                let days = buf.get_u32_le();\n                let hours = buf.get_u8();\n                let minutes = buf.get_u8();\n                let seconds = buf.get_u8();\n\n                let microseconds = if !buf.is_empty() { buf.get_u32_le() } else { 0 };\n\n                let whole_hours = days\n                    .checked_mul(24)\n                    .and_then(|days_to_hours| days_to_hours.checked_add(hours as u32))\n                    .ok_or(\"overflow calculating whole hours from `days * 24 + hours`\")?;\n\n                Ok(Self::new(\n                    sign,\n                    whole_hours,\n                    minutes,\n                    seconds,\n                    microseconds,\n                )?)\n            }\n            MySqlValueFormat::Text => parse(value.as_str()?),\n        }\n    }\n}\n\nimpl Encode<'_, MySql> for MySqlTime {\n    fn encode_by_ref(\n        &self,\n        buf: &mut <MySql as Database>::ArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        if self.is_zero() {\n            buf.put_u8(0);\n            return Ok(IsNull::No);\n        }\n\n        buf.put_u8(self.encoded_len());\n        buf.put_u8(self.sign.to_byte());\n\n        let TimeMagnitude {\n            hours: whole_hours,\n            minutes,\n            seconds,\n            microseconds,\n        } = self.magnitude;\n\n        let days = whole_hours / 24;\n        let hours = (whole_hours % 24) as u8;\n\n        buf.put_u32_le(days);\n        buf.put_u8(hours);\n        buf.put_u8(minutes);\n        buf.put_u8(seconds);\n\n        if microseconds != 0 {\n            buf.put_u32_le(microseconds);\n        }\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        self.encoded_len() as usize + 1\n    }\n}\n\n/// Convert [`MySqlTime`] from [`std::time::Duration`].\n///\n/// ### Note: Precision Truncation\n/// [`Duration`] supports nanosecond precision, but MySQL `TIME` values only support microsecond\n/// precision.\n///\n/// For simplicity, higher precision values are truncated when converting.\n/// If you prefer another rounding mode instead, you should apply that to the `Duration` first.\n///\n/// See also: [MySQL Manual, section 13.2.6: Fractional Seconds in Time Values](https://dev.mysql.com/doc/refman/8.3/en/fractional-seconds.html)\n///\n/// ### Errors:\n/// Returns [`MySqlTimeError::FieldRange`] if the given duration is longer than `838:59:59.999999`.\n///\nimpl TryFrom<Duration> for MySqlTime {\n    type Error = MySqlTimeError;\n\n    fn try_from(value: Duration) -> Result<Self, Self::Error> {\n        let hours = value.as_secs() / 3600;\n        let rem_seconds = value.as_secs() % 3600;\n        let minutes = (rem_seconds / 60) as u8;\n        let seconds = (rem_seconds % 60) as u8;\n\n        // Simply divides by 1000\n        let microseconds = value.subsec_micros();\n\n        Self::new(\n            MySqlTimeSign::Positive,\n            hours.try_into().map_err(|_| MySqlTimeError::FieldRange {\n                field: \"hours\",\n                max: Self::HOURS_MAX,\n                value: hours,\n            })?,\n            minutes,\n            seconds,\n            microseconds,\n        )\n    }\n}\n\nimpl MySqlTimeSign {\n    fn from_byte(b: u8) -> Result<Self, BoxDynError> {\n        match b {\n            0 => Ok(Self::Positive),\n            1 => Ok(Self::Negative),\n            other => Err(format!(\"expected 0 or 1 for TIME sign byte, got {other}\").into()),\n        }\n    }\n\n    fn to_byte(self) -> u8 {\n        match self {\n            // We can't use `#[repr(u8)]` because this is opposite of the ordering we want from `Ord`\n            Self::Negative => 1,\n            Self::Positive => 0,\n        }\n    }\n\n    fn signum(&self) -> i32 {\n        match self {\n            Self::Negative => -1,\n            Self::Positive => 1,\n        }\n    }\n\n    /// Returns `true` if positive, `false` if negative.\n    pub fn is_positive(&self) -> bool {\n        matches!(self, Self::Positive)\n    }\n\n    /// Returns `true` if negative, `false` if positive.\n    pub fn is_negative(&self) -> bool {\n        matches!(self, Self::Negative)\n    }\n}\n\nimpl Display for MySqlTimeSign {\n    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {\n        match self {\n            Self::Positive if f.sign_plus() => f.write_char('+'),\n            Self::Negative => f.write_char('-'),\n            _ => Ok(()),\n        }\n    }\n}\n\nimpl Type<MySql> for Duration {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTime::type_info()\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for Duration {\n    fn decode(value: <MySql as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        let time = MySqlTime::decode(value)?;\n\n        time.to_duration().ok_or_else(|| {\n            format!(\"`std::time::Duration` can only decode positive TIME values; got {time}\").into()\n        })\n    }\n}\n\n// Not exposing this as a `FromStr` impl currently because `MySqlTime` is not designed to be\n// a general interchange type.\nfn parse(text: &str) -> Result<MySqlTime, BoxDynError> {\n    let mut segments = text.split(':');\n\n    let hours = segments\n        .next()\n        .ok_or(\"expected hours segment, got nothing\")?;\n\n    let minutes = segments\n        .next()\n        .ok_or(\"expected minutes segment, got nothing\")?;\n\n    let seconds = segments\n        .next()\n        .ok_or(\"expected seconds segment, got nothing\")?;\n\n    // Include the sign in parsing for convenience;\n    // the allowed range of whole hours is much smaller than `i32`'s positive range.\n    let hours: i32 = hours\n        .parse()\n        .map_err(|e| format!(\"error parsing hours from {text:?} (segment {hours:?}): {e}\"))?;\n\n    let sign = if hours.is_negative() {\n        MySqlTimeSign::Negative\n    } else {\n        MySqlTimeSign::Positive\n    };\n\n    let hours = hours.unsigned_abs();\n\n    let minutes: u8 = minutes\n        .parse()\n        .map_err(|e| format!(\"error parsing minutes from {text:?} (segment {minutes:?}): {e}\"))?;\n\n    let (seconds, microseconds): (u8, u32) = if let Some((seconds, microseconds)) =\n        seconds.split_once('.')\n    {\n        (\n            seconds.parse().map_err(|e| {\n                format!(\"error parsing seconds from {text:?} (segment {seconds:?}): {e}\")\n            })?,\n            parse_microseconds(microseconds).map_err(|e| {\n                format!(\"error parsing microseconds from {text:?} (segment {microseconds:?}): {e}\")\n            })?,\n        )\n    } else {\n        (\n            seconds.parse().map_err(|e| {\n                format!(\"error parsing seconds from {text:?} (segment {seconds:?}): {e}\")\n            })?,\n            0,\n        )\n    };\n\n    Ok(MySqlTime::new(sign, hours, minutes, seconds, microseconds)?)\n}\n\n/// Parse microseconds from a fractional seconds string.\nfn parse_microseconds(micros: &str) -> Result<u32, BoxDynError> {\n    const EXPECTED_DIGITS: usize = 6;\n\n    match micros.len() {\n        0 => Err(\"empty string\".into()),\n        len @ ..=EXPECTED_DIGITS => {\n            // Fewer than 6 digits, multiply to the correct magnitude\n            let micros: u32 = micros.parse()?;\n            // cast cannot overflow\n            #[allow(clippy::cast_possible_truncation)]\n            Ok(micros * 10u32.pow((EXPECTED_DIGITS - len) as u32))\n        }\n        // More digits than expected, truncate\n        _ => Ok(micros[..EXPECTED_DIGITS].parse()?),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::MySqlTime;\n    use crate::types::MySqlTimeSign;\n\n    use super::parse_microseconds;\n\n    #[test]\n    fn test_display() {\n        assert_eq!(MySqlTime::ZERO.to_string(), \"0:00:00\");\n\n        assert_eq!(format!(\"{:.0}\", MySqlTime::ZERO), \"0:00:00\");\n\n        assert_eq!(format!(\"{:.3}\", MySqlTime::ZERO), \"0:00:00.000\");\n\n        assert_eq!(format!(\"{:.6}\", MySqlTime::ZERO), \"0:00:00.000000\");\n\n        assert_eq!(format!(\"{:.9}\", MySqlTime::ZERO), \"0:00:00.000000000\");\n\n        assert_eq!(format!(\"{:.0}\", MySqlTime::MAX), \"838:59:59\");\n\n        assert_eq!(format!(\"{:.3}\", MySqlTime::MAX), \"838:59:59.000\");\n\n        assert_eq!(format!(\"{:.6}\", MySqlTime::MAX), \"838:59:59.000000\");\n\n        assert_eq!(format!(\"{:.9}\", MySqlTime::MAX), \"838:59:59.000000000\");\n\n        assert_eq!(format!(\"{:+.0}\", MySqlTime::MAX), \"+838:59:59\");\n\n        assert_eq!(format!(\"{:+.3}\", MySqlTime::MAX), \"+838:59:59.000\");\n\n        assert_eq!(format!(\"{:+.6}\", MySqlTime::MAX), \"+838:59:59.000000\");\n\n        assert_eq!(format!(\"{:+.9}\", MySqlTime::MAX), \"+838:59:59.000000000\");\n\n        assert_eq!(format!(\"{:.0}\", MySqlTime::MIN), \"-838:59:59\");\n\n        assert_eq!(format!(\"{:.3}\", MySqlTime::MIN), \"-838:59:59.000\");\n\n        assert_eq!(format!(\"{:.6}\", MySqlTime::MIN), \"-838:59:59.000000\");\n\n        assert_eq!(format!(\"{:.9}\", MySqlTime::MIN), \"-838:59:59.000000000\");\n\n        let positive = MySqlTime::new(MySqlTimeSign::Positive, 123, 45, 56, 890011).unwrap();\n\n        assert_eq!(positive.to_string(), \"123:45:56.890011\");\n        assert_eq!(format!(\"{positive:.0}\"), \"123:45:56\");\n        assert_eq!(format!(\"{positive:.3}\"), \"123:45:56.890\");\n        assert_eq!(format!(\"{positive:.6}\"), \"123:45:56.890011\");\n        assert_eq!(format!(\"{positive:.9}\"), \"123:45:56.890011000\");\n\n        assert_eq!(format!(\"{positive:+.0}\"), \"+123:45:56\");\n        assert_eq!(format!(\"{positive:+.3}\"), \"+123:45:56.890\");\n        assert_eq!(format!(\"{positive:+.6}\"), \"+123:45:56.890011\");\n        assert_eq!(format!(\"{positive:+.9}\"), \"+123:45:56.890011000\");\n\n        let negative = MySqlTime::new(MySqlTimeSign::Negative, 123, 45, 56, 890011).unwrap();\n\n        assert_eq!(negative.to_string(), \"-123:45:56.890011\");\n        assert_eq!(format!(\"{negative:.0}\"), \"-123:45:56\");\n        assert_eq!(format!(\"{negative:.3}\"), \"-123:45:56.890\");\n        assert_eq!(format!(\"{negative:.6}\"), \"-123:45:56.890011\");\n        assert_eq!(format!(\"{negative:.9}\"), \"-123:45:56.890011000\");\n    }\n\n    #[test]\n    fn test_parse_microseconds() {\n        assert_eq!(parse_microseconds(\"010\").unwrap(), 10_000);\n\n        assert_eq!(parse_microseconds(\"0100000000\").unwrap(), 10_000);\n\n        assert_eq!(parse_microseconds(\"890\").unwrap(), 890_000);\n\n        assert_eq!(parse_microseconds(\"0890\").unwrap(), 89_000);\n\n        assert_eq!(\n            // Case in point about not exposing this:\n            // we always truncate excess precision because it's simpler than rounding\n            // and MySQL should never return a higher precision.\n            parse_microseconds(\"123456789\").unwrap(),\n            123456,\n        );\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/rust_decimal.rs",
    "content": "use rust_decimal::Decimal;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::io::MySqlBufMutExt;\nuse crate::protocol::text::ColumnType;\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl Type<MySql> for Decimal {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::NewDecimal)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(ty.r#type, ColumnType::Decimal | ColumnType::NewDecimal)\n    }\n}\n\nimpl Encode<'_, MySql> for Decimal {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for Decimal {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(value.as_str()?.parse()?)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/str.rs",
    "content": "use std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::collation::Collation;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::io::MySqlBufMutExt;\nuse crate::protocol::text::{ColumnFlags, ColumnType};\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl Type<MySql> for str {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo {\n            r#type: ColumnType::VarString, // VARCHAR\n            flags: ColumnFlags::empty(),\n            // Doesn't matter because we never send this.\n            collation: Collation::UTF8MB4_GENERAL_CI,\n            max_size: None,\n        }\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        // TODO: Support more collations being returned from SQL?\n        matches!(\n            ty.r#type,\n            ColumnType::VarChar\n                | ColumnType::Blob\n                | ColumnType::TinyBlob\n                | ColumnType::MediumBlob\n                | ColumnType::LongBlob\n                | ColumnType::String\n                | ColumnType::VarString\n                | ColumnType::Enum\n        )\n            // Any collation that *isn't* `binary` generally indicates string data.\n            // The actual collation used for storage doesn't matter, \n            // because the server will transcode to the charset we specify.\n            //\n            // See comment in `src/collation.rs` for details.\n            && ty.collation != Collation::BINARY\n    }\n}\n\nimpl Encode<'_, MySql> for &'_ str {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(self);\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for &'r str {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        value.as_str()\n    }\n}\n\nimpl Type<MySql> for String {\n    fn type_info() -> MySqlTypeInfo {\n        <str as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <str as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Decode<'_, MySql> for String {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        <&str as Decode<MySql>>::decode(value).map(ToOwned::to_owned)\n    }\n}\n\nforward_encode_impl!(Arc<str>, &str, MySql);\nforward_encode_impl!(Rc<str>, &str, MySql);\nforward_encode_impl!(Cow<'_, str>, &str, MySql);\nforward_encode_impl!(Box<str>, &str, MySql);\nforward_encode_impl!(String, &str, MySql);\n"
  },
  {
    "path": "sqlx-mysql/src/types/text.rs",
    "content": "use crate::{MySql, MySqlTypeInfo, MySqlValueRef};\nuse sqlx_core::decode::Decode;\nuse sqlx_core::encode::{Encode, IsNull};\nuse sqlx_core::error::BoxDynError;\nuse sqlx_core::types::{Text, Type};\nuse std::fmt::Display;\nuse std::str::FromStr;\n\nimpl<T> Type<MySql> for Text<T> {\n    fn type_info() -> MySqlTypeInfo {\n        <String as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <String as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl<T> Encode<'_, MySql> for Text<T>\nwhere\n    T: Display,\n{\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        // We can't really do the trick like with Postgres where we reserve the space for the\n        // length up-front and then overwrite it later, because MySQL appears to enforce that\n        // length-encoded integers use the smallest encoding for the value:\n        // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_basic_dt_integers.html#sect_protocol_basic_dt_int_le\n        //\n        // So we'd have to reserve space for the max-width encoding, format into the buffer,\n        // then figure out how many bytes our length-encoded integer needs to be and move the\n        // value bytes down to use up the empty space.\n        //\n        // Copying from a completely separate buffer instead is easier. It may or may not be faster\n        // or slower depending on a ton of different variables, but I don't currently have the time\n        // to implement both approaches and compare their performance.\n        Encode::<MySql>::encode(self.0.to_string(), buf)\n    }\n}\n\nimpl<'r, T> Decode<'r, MySql> for Text<T>\nwhere\n    T: FromStr,\n    BoxDynError: From<<T as FromStr>::Err>,\n{\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        let s: &str = Decode::<MySql>::decode(value)?;\n        Ok(Self(s.parse()?))\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/time.rs",
    "content": "use byteorder::{ByteOrder, LittleEndian};\nuse bytes::Buf;\nuse sqlx_core::database::Database;\nuse time::macros::format_description;\nuse time::{Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::{BoxDynError, UnexpectedNullError};\nuse crate::protocol::text::ColumnType;\nuse crate::type_info::MySqlTypeInfo;\nuse crate::types::{MySqlTime, MySqlTimeSign, Type};\nuse crate::{MySql, MySqlValueFormat, MySqlValueRef};\n\nimpl Type<MySql> for OffsetDateTime {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Timestamp)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        matches!(ty.r#type, ColumnType::Datetime | ColumnType::Timestamp)\n    }\n}\n\nimpl Encode<'_, MySql> for OffsetDateTime {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        let utc_dt = self.to_offset(UtcOffset::UTC);\n        let primitive_dt = PrimitiveDateTime::new(utc_dt.date(), utc_dt.time());\n\n        Encode::<MySql>::encode(primitive_dt, buf)\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for OffsetDateTime {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        let primitive: PrimitiveDateTime = Decode::<MySql>::decode(value)?;\n\n        Ok(primitive.assume_utc())\n    }\n}\n\nimpl Type<MySql> for Time {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Time)\n    }\n}\n\nimpl Encode<'_, MySql> for Time {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        let len = time_encoded_len(self);\n        buf.push(len);\n\n        // sign byte: Time is never negative\n        buf.push(0);\n\n        // Number of days in the interval; always 0 for time-of-day values.\n        // https://mariadb.com/kb/en/resultset-row/#teimstamp-binary-encoding\n        buf.extend_from_slice(&[0_u8; 4]);\n\n        encode_time(self, len > 8, buf);\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        time_encoded_len(self) as usize + 1 // plus length byte\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for Time {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                // Should never panic.\n                MySqlTime::decode(value)?.try_into()\n            }\n\n            // Retaining this parsing for now as it allows us to cross-check our impl.\n            MySqlValueFormat::Text => Time::parse(\n                value.as_str()?,\n                &format_description!(\"[hour]:[minute]:[second].[subsecond]\"),\n            )\n            .map_err(Into::into),\n        }\n    }\n}\n\nimpl TryFrom<MySqlTime> for Time {\n    type Error = BoxDynError;\n\n    fn try_from(time: MySqlTime) -> Result<Self, Self::Error> {\n        if !time.is_valid_time_of_day() {\n            return Err(format!(\"MySqlTime value out of range for `time::Time`: {time}\").into());\n        }\n\n        #[allow(clippy::cast_possible_truncation)]\n        Ok(Time::from_hms_micro(\n            // `is_valid_time_of_day()` ensures this won't overflow\n            time.hours() as u8,\n            time.minutes(),\n            time.seconds(),\n            time.microseconds(),\n        )?)\n    }\n}\n\nimpl From<MySqlTime> for time::Duration {\n    fn from(time: MySqlTime) -> Self {\n        // `subsec_nanos()` is guaranteed to be between 0 and 10^9\n        #[allow(clippy::cast_possible_wrap)]\n        time::Duration::new(time.whole_seconds_signed(), time.subsec_nanos() as i32)\n    }\n}\n\nimpl TryFrom<time::Duration> for MySqlTime {\n    type Error = BoxDynError;\n\n    fn try_from(value: time::Duration) -> Result<Self, Self::Error> {\n        let sign = if value.is_negative() {\n            MySqlTimeSign::Negative\n        } else {\n            MySqlTimeSign::Positive\n        };\n\n        // Similar to `TryFrom<chrono::TimeDelta>`, use `std::time::Duration` as an intermediate.\n        Ok(MySqlTime::try_from(std::time::Duration::try_from(value.abs())?)?.with_sign(sign))\n    }\n}\n\nimpl Type<MySql> for time::Duration {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTime::type_info()\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for time::Duration {\n    fn decode(value: <MySql as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(MySqlTime::decode(value)?.into())\n    }\n}\n\nimpl Type<MySql> for Date {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Date)\n    }\n}\n\nimpl Encode<'_, MySql> for Date {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.push(4);\n\n        encode_date(self, buf)?;\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        5\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for Date {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                let buf = value.as_bytes()?;\n\n                // Row decoding should leave the length byte on the front.\n                if buf.is_empty() {\n                    return Err(\"empty buffer\".into());\n                }\n\n                Ok(decode_date(&buf[1..])?.ok_or(UnexpectedNullError)?)\n            }\n            MySqlValueFormat::Text => {\n                let s = value.as_str()?;\n                Date::parse(s, &format_description!(\"[year]-[month]-[day]\")).map_err(Into::into)\n            }\n        }\n    }\n}\n\nimpl Type<MySql> for PrimitiveDateTime {\n    fn type_info() -> MySqlTypeInfo {\n        MySqlTypeInfo::binary(ColumnType::Datetime)\n    }\n}\n\nimpl Encode<'_, MySql> for PrimitiveDateTime {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        let len = primitive_dt_encoded_len(self);\n        buf.push(len);\n\n        encode_date(&self.date(), buf)?;\n\n        if len > 4 {\n            encode_time(&self.time(), len > 7, buf);\n        }\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        primitive_dt_encoded_len(self) as usize + 1 // plus length byte\n    }\n}\n\nimpl<'r> Decode<'r, MySql> for PrimitiveDateTime {\n    fn decode(value: MySqlValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            MySqlValueFormat::Binary => {\n                let mut buf = value.as_bytes()?;\n\n                if buf.is_empty() {\n                    return Err(\"empty buffer\".into());\n                }\n\n                let len = buf.get_u8();\n\n                let date = decode_date(buf)?.ok_or(UnexpectedNullError)?;\n\n                let dt = if len > 4 {\n                    date.with_time(decode_time(&buf[4..])?)\n                } else {\n                    date.midnight()\n                };\n\n                Ok(dt)\n            }\n\n            MySqlValueFormat::Text => {\n                let s = value.as_str()?;\n\n                // If there are no nanoseconds parse without them\n                if s.contains('.') {\n                    PrimitiveDateTime::parse(\n                        s,\n                        &format_description!(\n                            \"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]\"\n                        ),\n                    )\n                    .map_err(Into::into)\n                } else {\n                    PrimitiveDateTime::parse(\n                        s,\n                        &format_description!(\"[year]-[month]-[day] [hour]:[minute]:[second]\"),\n                    )\n                    .map_err(Into::into)\n                }\n            }\n        }\n    }\n}\n\nfn encode_date(date: &Date, buf: &mut Vec<u8>) -> Result<(), BoxDynError> {\n    // MySQL supports years from 1000 - 9999\n    let year =\n        u16::try_from(date.year()).map_err(|_| format!(\"Date out of range for Mysql: {date}\"))?;\n\n    buf.extend_from_slice(&year.to_le_bytes());\n    buf.push(date.month().into());\n    buf.push(date.day());\n\n    Ok(())\n}\n\nfn decode_date(buf: &[u8]) -> Result<Option<Date>, BoxDynError> {\n    if buf.is_empty() {\n        // zero buffer means a zero date (null)\n        return Ok(None);\n    }\n\n    Date::from_calendar_date(\n        LittleEndian::read_u16(buf) as i32,\n        time::Month::try_from(buf[2])?,\n        buf[3],\n    )\n    .map_err(Into::into)\n    .map(Some)\n}\n\nfn encode_time(time: &Time, include_micros: bool, buf: &mut Vec<u8>) {\n    buf.push(time.hour());\n    buf.push(time.minute());\n    buf.push(time.second());\n\n    if include_micros {\n        buf.extend(&(time.nanosecond() / 1000).to_le_bytes());\n    }\n}\n\nfn decode_time(mut buf: &[u8]) -> Result<Time, BoxDynError> {\n    let hour = buf.get_u8();\n    let minute = buf.get_u8();\n    let seconds = buf.get_u8();\n\n    let micros = if !buf.is_empty() {\n        // microseconds : int<EOF>\n        buf.get_uint_le(buf.len())\n    } else {\n        0\n    };\n\n    let micros = u32::try_from(micros)\n        .map_err(|_| format!(\"MySQL returned microseconds out of range: {micros}\"))?;\n\n    Time::from_hms_micro(hour, minute, seconds, micros)\n        .map_err(|e| format!(\"Time out of range for MySQL: {e}\").into())\n}\n\n#[inline(always)]\nfn primitive_dt_encoded_len(time: &PrimitiveDateTime) -> u8 {\n    // to save space the packet can be compressed:\n    match (time.hour(), time.minute(), time.second(), time.nanosecond()) {\n        // if hour, minutes, seconds and micro_seconds are all 0,\n        // length is 4 and no other field is sent\n        (0, 0, 0, 0) => 4,\n\n        // if micro_seconds is 0, length is 7\n        // and micro_seconds is not sent\n        (_, _, _, 0) => 7,\n\n        // otherwise length is 11\n        (_, _, _, _) => 11,\n    }\n}\n\n#[inline(always)]\nfn time_encoded_len(time: &Time) -> u8 {\n    if time.nanosecond() == 0 {\n        // if micro_seconds is 0, length is 8 and micro_seconds is not sent\n        8\n    } else {\n        // otherwise length is 12\n        12\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/uint.rs",
    "content": "use crate::collation::Collation;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::protocol::text::{ColumnFlags, ColumnType};\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueFormat, MySqlValueRef};\nuse byteorder::{ByteOrder, LittleEndian};\n\nfn uint_type_info(ty: ColumnType) -> MySqlTypeInfo {\n    MySqlTypeInfo {\n        r#type: ty,\n        flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,\n        collation: Collation::BINARY,\n        max_size: None,\n    }\n}\n\nfn uint_compatible(ty: &MySqlTypeInfo) -> bool {\n    matches!(\n        ty.r#type,\n        ColumnType::Tiny\n            | ColumnType::Short\n            | ColumnType::Long\n            | ColumnType::Int24\n            | ColumnType::LongLong\n            | ColumnType::Year\n            | ColumnType::Bit\n    ) && ty.flags.contains(ColumnFlags::UNSIGNED)\n}\n\nimpl Type<MySql> for u8 {\n    fn type_info() -> MySqlTypeInfo {\n        uint_type_info(ColumnType::Tiny)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        uint_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for u16 {\n    fn type_info() -> MySqlTypeInfo {\n        uint_type_info(ColumnType::Short)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        uint_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for u32 {\n    fn type_info() -> MySqlTypeInfo {\n        uint_type_info(ColumnType::Long)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        uint_compatible(ty)\n    }\n}\n\nimpl Type<MySql> for u64 {\n    fn type_info() -> MySqlTypeInfo {\n        uint_type_info(ColumnType::LongLong)\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        uint_compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for u8 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for u16 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for u32 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, MySql> for u64 {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_le_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nfn uint_decode(value: MySqlValueRef<'_>) -> Result<u64, BoxDynError> {\n    if value.type_info.r#type == ColumnType::Bit {\n        // NOTE: Regardless of the value format, there is raw binary data here\n\n        let buf = value.as_bytes()?;\n        let mut value: u64 = 0;\n\n        for b in buf {\n            value = (*b as u64) | (value << 8);\n        }\n\n        return Ok(value);\n    }\n\n    Ok(match value.format() {\n        MySqlValueFormat::Text => value.as_str()?.parse()?,\n\n        MySqlValueFormat::Binary => {\n            let buf = value.as_bytes()?;\n\n            // Check conditions that could cause `read_uint()` to panic.\n            if buf.is_empty() {\n                return Err(\"empty buffer\".into());\n            }\n\n            if buf.len() > 8 {\n                return Err(format!(\n                    \"expected no more than 8 bytes for unsigned integer value, got {}\",\n                    buf.len()\n                )\n                .into());\n            }\n\n            LittleEndian::read_uint(buf, buf.len())\n        }\n    })\n}\n\nimpl Decode<'_, MySql> for u8 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        uint_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Decode<'_, MySql> for u16 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        uint_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Decode<'_, MySql> for u32 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        uint_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Decode<'_, MySql> for u64 {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        uint_decode(value)\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/types/uuid.rs",
    "content": "use uuid::{\n    fmt::{Hyphenated, Simple},\n    Uuid,\n};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::io::MySqlBufMutExt;\nuse crate::types::Type;\nuse crate::{MySql, MySqlTypeInfo, MySqlValueRef};\n\nimpl Type<MySql> for Uuid {\n    fn type_info() -> MySqlTypeInfo {\n        <&[u8] as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&[u8] as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for Uuid {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_bytes_lenenc(self.as_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for Uuid {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        // delegate to the &[u8] type to decode from MySQL\n        let bytes = <&[u8] as Decode<MySql>>::decode(value)?;\n\n        if bytes.len() != 16 {\n            return Err(format!(\n                \"Expected 16 bytes, got {}; `Uuid` uses binary format for MySQL/MariaDB. \\\n                 For text-formatted UUIDs, use `uuid::fmt::Hyphenated` instead of `Uuid`.\",\n                bytes.len(),\n            )\n            .into());\n        }\n\n        // construct a Uuid from the returned bytes\n        Uuid::from_slice(bytes).map_err(Into::into)\n    }\n}\n\nimpl Type<MySql> for Hyphenated {\n    fn type_info() -> MySqlTypeInfo {\n        <&str as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&str as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for Hyphenated {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for Hyphenated {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        // delegate to the &str type to decode from MySQL\n        let text = <&str as Decode<MySql>>::decode(value)?;\n\n        // parse a UUID from the text\n        Uuid::parse_str(text)\n            .map_err(Into::into)\n            .map(|u| u.hyphenated())\n    }\n}\n\nimpl Type<MySql> for Simple {\n    fn type_info() -> MySqlTypeInfo {\n        <&str as Type<MySql>>::type_info()\n    }\n\n    fn compatible(ty: &MySqlTypeInfo) -> bool {\n        <&str as Type<MySql>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, MySql> for Simple {\n    fn encode_by_ref(&self, buf: &mut Vec<u8>) -> Result<IsNull, BoxDynError> {\n        buf.put_str_lenenc(&self.to_string());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, MySql> for Simple {\n    fn decode(value: MySqlValueRef<'_>) -> Result<Self, BoxDynError> {\n        // delegate to the &str type to decode from MySQL\n        let text = <&str as Decode<MySql>>::decode(value)?;\n\n        // parse a UUID from the text\n        Uuid::parse_str(text)\n            .map_err(Into::into)\n            .map(|u| u.simple())\n    }\n}\n"
  },
  {
    "path": "sqlx-mysql/src/value.rs",
    "content": "use std::borrow::Cow;\nuse std::str::from_utf8;\n\nuse bytes::Bytes;\npub(crate) use sqlx_core::value::*;\n\nuse crate::error::{BoxDynError, UnexpectedNullError};\nuse crate::protocol::text::ColumnType;\nuse crate::{MySql, MySqlTypeInfo};\n\n#[derive(Debug, Clone, Copy)]\n#[repr(u8)]\npub enum MySqlValueFormat {\n    Text,\n    Binary,\n}\n\n/// Implementation of [`Value`] for MySQL.\n#[derive(Clone)]\npub struct MySqlValue {\n    value: Option<Bytes>,\n    type_info: MySqlTypeInfo,\n    format: MySqlValueFormat,\n}\n\n/// Implementation of [`ValueRef`] for MySQL.\n#[derive(Clone)]\npub struct MySqlValueRef<'r> {\n    pub(crate) value: Option<&'r [u8]>,\n    pub(crate) row: Option<&'r Bytes>,\n    pub(crate) type_info: MySqlTypeInfo,\n    pub(crate) format: MySqlValueFormat,\n}\n\nimpl<'r> MySqlValueRef<'r> {\n    pub(crate) fn format(&self) -> MySqlValueFormat {\n        self.format\n    }\n\n    pub(crate) fn as_bytes(&self) -> Result<&'r [u8], BoxDynError> {\n        match &self.value {\n            Some(v) => Ok(v),\n            None => Err(UnexpectedNullError.into()),\n        }\n    }\n\n    pub(crate) fn as_str(&self) -> Result<&'r str, BoxDynError> {\n        Ok(from_utf8(self.as_bytes()?)?)\n    }\n}\n\nimpl Value for MySqlValue {\n    type Database = MySql;\n\n    fn as_ref(&self) -> MySqlValueRef<'_> {\n        MySqlValueRef {\n            value: self.value.as_deref(),\n            row: None,\n            type_info: self.type_info.clone(),\n            format: self.format,\n        }\n    }\n\n    fn type_info(&self) -> Cow<'_, MySqlTypeInfo> {\n        Cow::Borrowed(&self.type_info)\n    }\n\n    fn is_null(&self) -> bool {\n        is_null(self.value.as_deref(), &self.type_info)\n    }\n}\n\nimpl<'r> ValueRef<'r> for MySqlValueRef<'r> {\n    type Database = MySql;\n\n    fn to_owned(&self) -> MySqlValue {\n        let value = match (self.row, self.value) {\n            (Some(row), Some(value)) => Some(row.slice_ref(value)),\n\n            (None, Some(value)) => Some(Bytes::copy_from_slice(value)),\n\n            _ => None,\n        };\n\n        MySqlValue {\n            value,\n            format: self.format,\n            type_info: self.type_info.clone(),\n        }\n    }\n\n    fn type_info(&self) -> Cow<'_, MySqlTypeInfo> {\n        Cow::Borrowed(&self.type_info)\n    }\n\n    #[inline]\n    fn is_null(&self) -> bool {\n        is_null(self.value, &self.type_info)\n    }\n}\n\nfn is_null(value: Option<&[u8]>, ty: &MySqlTypeInfo) -> bool {\n    if let Some(value) = value {\n        // zero dates and date times should be treated the same as NULL\n        if matches!(\n            ty.r#type,\n            ColumnType::Date | ColumnType::Timestamp | ColumnType::Datetime\n        ) && value.starts_with(b\"\\0\")\n        {\n            return true;\n        }\n    }\n\n    value.is_none()\n}\n"
  },
  {
    "path": "sqlx-postgres/Cargo.toml",
    "content": "[package]\nname = \"sqlx-postgres\"\ndocumentation = \"https://docs.rs/sqlx\"\ndescription = \"PostgreSQL driver implementation for SQLx. Not for direct use; see the `sqlx` crate for details.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n[features]\nany = [\"sqlx-core/any\"]\njson = [\"dep:serde\", \"dep:serde_json\", \"sqlx-core/json\"]\nmigrate = [\"sqlx-core/migrate\"]\noffline = [\"json\", \"sqlx-core/offline\", \"smallvec/serde\"]\n\n# Type Integration features\nbigdecimal = [\"dep:bigdecimal\", \"dep:num-bigint\", \"sqlx-core/bigdecimal\"]\nbit-vec = [\"dep:bit-vec\", \"sqlx-core/bit-vec\"]\nchrono = [\"dep:chrono\", \"sqlx-core/chrono\"]\nipnet = [\"dep:ipnet\", \"sqlx-core/ipnet\"]\nipnetwork = [\"dep:ipnetwork\", \"sqlx-core/ipnetwork\"]\nmac_address = [\"dep:mac_address\", \"sqlx-core/mac_address\"]\nrust_decimal = [\"dep:rust_decimal\", \"rust_decimal/maths\", \"sqlx-core/rust_decimal\"]\ntime = [\"dep:time\", \"sqlx-core/time\"]\nuuid = [\"dep:uuid\", \"sqlx-core/uuid\"]\n\n[dependencies]\n# Futures crates\nfutures-channel = { version = \"0.3.19\", default-features = false, features = [\"sink\", \"alloc\", \"std\"] }\nfutures-core = { version = \"0.3.19\", default-features = false }\nfutures-util = { version = \"0.3.19\", default-features = false, features = [\"alloc\", \"sink\", \"io\"] }\n\n# Cryptographic Primitives\ncrc = \"3.0.0\"\nhkdf = \"0.12.0\"\nhmac = { version = \"0.12.0\", default-features = false, features = [\"reset\"]}\nmd-5 = { version = \"0.10.0\", default-features = false }\nrand = { version = \"0.8.4\", default-features = false, features = [\"std\", \"std_rng\"] }\nsha2 = { version = \"0.10.0\", default-features = false }\n\n# Type Integrations (versions inherited from `[workspace.dependencies]`)\nbigdecimal = { workspace = true, optional = true }\nbit-vec = { workspace = true, optional = true }\nchrono = { workspace = true, optional = true }\nipnet = { workspace = true, optional = true }\nipnetwork = { workspace = true, optional = true }\nmac_address = { workspace = true, optional = true }\nrust_decimal = { workspace = true, optional = true }\ntime = { workspace = true, optional = true }\nuuid = { workspace = true, optional = true }\n\n# Misc\natoi = \"2.0\"\nbase64 = { version = \"0.22.0\", default-features = false, features = [\"std\"] }\nbitflags = { version = \"2\", default-features = false }\nbyteorder = { version = \"1.4.3\", default-features = false, features = [\"std\"] }\nhex = \"0.4.3\"\nitoa = \"1.0.1\"\nlog = \"0.4.18\"\nmemchr = { version = \"2.4.1\", default-features = false }\nnum-bigint = { version = \"0.4.3\", optional = true }\nsmallvec = { version = \"1.7.0\" }\nstringprep = \"0.1.2\"\ntracing = { version = \"0.1.37\", features = [\"log\"] }\nwhoami = { version = \"2.0.2\", default-features = false }\n\ndotenvy.workspace = true\nthiserror.workspace = true\n\nserde = { version = \"1.0.144\", optional = true, features = [\"derive\"] }\nserde_json = { version = \"1.0.85\", optional = true, features = [\"raw_value\"] }\n\n[dependencies.sqlx-core]\nworkspace = true\n\n[dev-dependencies.sqlx]\n# FIXME: https://github.com/rust-lang/cargo/issues/15622\n# workspace = true\npath = \"..\"\nfeatures = [\"postgres\", \"derive\"]\n\n[target.'cfg(target_os = \"windows\")'.dependencies]\netcetera = \"0.10.0\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "sqlx-postgres/src/advisory_lock.rs",
    "content": "use crate::error::Result;\nuse crate::Either;\nuse crate::PgConnection;\nuse hkdf::Hkdf;\nuse sha2::Sha256;\nuse std::ops::{Deref, DerefMut};\nuse std::sync::Arc;\nuse std::sync::OnceLock;\n\n/// A mutex-like type utilizing [Postgres advisory locks].\n///\n/// Advisory locks are a mechanism provided by Postgres to have mutually exclusive or shared\n/// locks tracked in the database with application-defined semantics, as opposed to the standard\n/// row-level or table-level locks which may not fit all use-cases.\n///\n/// This API provides a convenient wrapper for generating and storing the integer keys that\n/// advisory locks use, as well as RAII guards for releasing advisory locks when they fall out\n/// of scope.\n///\n/// This API only handles session-scoped advisory locks (explicitly locked and unlocked, or\n/// automatically released when a connection is closed).\n///\n/// It is also possible to use transaction-scoped locks but those can be used by beginning a\n/// transaction and calling the appropriate lock functions (e.g. `SELECT pg_advisory_xact_lock()`)\n/// manually, and cannot be explicitly released, but are automatically released when a transaction\n/// ends (is committed or rolled back).\n///\n/// Session-level locks can be acquired either inside or outside a transaction and are not\n/// tied to transaction semantics; a lock acquired inside a transaction is still held when that\n/// transaction is committed or rolled back, until explicitly released or the connection is closed.\n///\n/// Locks can be acquired in either shared or exclusive modes, which can be thought of as read locks\n/// and write locks, respectively. Multiple shared locks are allowed for the same key, but a single\n/// exclusive lock prevents any other lock being taken for a given key until it is released.\n///\n/// [Postgres advisory locks]: https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS\n#[derive(Debug, Clone)]\npub struct PgAdvisoryLock {\n    key: PgAdvisoryLockKey,\n    /// The query to execute to release this lock.\n    release_query: Arc<OnceLock<String>>,\n}\n\n/// A key type natively used by Postgres advisory locks.\n///\n/// Currently, Postgres advisory locks have two different key spaces: one keyed by a single\n/// 64-bit integer, and one keyed by a pair of two 32-bit integers. The Postgres docs\n/// specify that these key spaces \"do not overlap\":\n///\n/// <https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS>\n///\n/// The documentation for the `pg_locks` system view explains further how advisory locks\n/// are treated in Postgres:\n///\n/// <https://www.postgresql.org/docs/current/view-pg-locks.html>\n#[derive(Debug, Clone, PartialEq, Eq)]\n#[non_exhaustive]\npub enum PgAdvisoryLockKey {\n    /// The keyspace designated by a single 64-bit integer.\n    ///\n    /// When [PgAdvisoryLock] is constructed with [::new()][PgAdvisoryLock::new()],\n    /// this is the keyspace used.\n    BigInt(i64),\n    /// The keyspace designated by two 32-bit integers.\n    IntPair(i32, i32),\n}\n\n/// A wrapper for `PgConnection` (or a similar type) that represents a held Postgres advisory lock.\n///\n/// Can be acquired by [`PgAdvisoryLock::acquire()`] or [`PgAdvisoryLock::try_acquire()`].\n/// Released on-drop or via [`Self::release_now()`].\n///\n/// ### Note: Release-on-drop is not immediate!\n/// On drop, this guard queues a `pg_advisory_unlock()` call on the connection which will be\n/// flushed to the server the next time it is used, or when it is returned to\n/// a [`PgPool`][crate::PgPool] in the case of\n/// [`PoolConnection<Postgres>`][crate::pool::PoolConnection].\n///\n/// This means the lock is not actually released as soon as the guard is dropped. To ensure the\n/// lock is eagerly released, you can call [`.release_now().await`][Self::release_now()].\npub struct PgAdvisoryLockGuard<C: AsMut<PgConnection>> {\n    lock: PgAdvisoryLock,\n    conn: Option<C>,\n}\n\nimpl PgAdvisoryLock {\n    /// Construct a `PgAdvisoryLock` using the given string as a key.\n    ///\n    /// This is intended to make it easier to use an advisory lock by using a human-readable string\n    /// for a key as opposed to manually generating a unique integer key. The generated integer key\n    /// is guaranteed to be stable and in the single 64-bit integer keyspace\n    /// (see [`PgAdvisoryLockKey`] for details).\n    ///\n    /// This is done by applying the [Hash-based Key Derivation Function (HKDF; IETF RFC 5869)][hkdf]\n    /// to the bytes of the input string, but in a way that the calculated integer is unlikely\n    /// to collide with any similar implementations (although we don't currently know of any).\n    /// See the source of this method for details.\n    ///\n    /// [hkdf]: https://datatracker.ietf.org/doc/html/rfc5869\n    /// ### Example\n    /// ```rust\n    /// use sqlx::postgres::{PgAdvisoryLock, PgAdvisoryLockKey};\n    ///\n    /// let lock = PgAdvisoryLock::new(\"my first Postgres advisory lock!\");\n    /// // Negative values are fine because of how Postgres treats advisory lock keys.\n    /// // See the documentation for the `pg_locks` system view for details.\n    /// assert_eq!(lock.key(), &PgAdvisoryLockKey::BigInt(-5560419505042474287));\n    /// ```\n    pub fn new(key_string: impl AsRef<str>) -> Self {\n        let input_key_material = key_string.as_ref();\n\n        // HKDF was chosen because it is designed to concentrate the entropy in a variable-length\n        // input key and produce a higher quality but reduced-length output key with a\n        // well-specified and reproducible algorithm.\n        //\n        // Granted, the input key is usually meant to be pseudorandom and not human readable,\n        // but we're not trying to produce an unguessable value by any means; just one that's as\n        // unlikely to already be in use as possible, but still deterministic.\n        //\n        // SHA-256 was chosen as the hash function because it's already used in the Postgres driver,\n        // which should save on codegen and optimization.\n\n        // We don't supply a salt as that is intended to be random, but we want a deterministic key.\n        let hkdf = Hkdf::<Sha256>::new(None, input_key_material.as_bytes());\n\n        let mut output_key_material = [0u8; 8];\n\n        // The first string is the \"info\" string of the HKDF which is intended to tie the output\n        // exclusively to SQLx. This should avoid collisions with implementations using a similar\n        // strategy. If you _want_ this to match some other implementation then you should get\n        // the calculated integer key from it and use that directly.\n        //\n        // Do *not* change this string as it will affect the output!\n        hkdf.expand(\n            b\"SQLx (Rust) Postgres advisory lock\",\n            &mut output_key_material,\n        )\n        // `Hkdf::expand()` only returns an error if you ask for more than 255 times the digest size.\n        // This is specified by RFC 5869 but not elaborated upon:\n        // https://datatracker.ietf.org/doc/html/rfc5869#section-2.3\n        // Since we're only asking for 8 bytes, this error shouldn't be returned.\n        .expect(\"BUG: `output_key_material` should be of acceptable length\");\n\n        // For ease of use, this method assumes the user doesn't care which keyspace is used.\n        //\n        // It doesn't seem likely that someone would care about using the `(int, int)` keyspace\n        // specifically unless they already had keys to use, in which case they wouldn't\n        // care about this method. That's why we also provide `with_key()`.\n        //\n        // The choice of `from_le_bytes()` is mostly due to x86 being the most popular\n        // architecture for server software, so it should be a no-op there.\n        let key = PgAdvisoryLockKey::BigInt(i64::from_le_bytes(output_key_material));\n\n        tracing::trace!(\n            ?key,\n            key_string = ?input_key_material,\n            \"generated key from key string\",\n        );\n\n        Self::with_key(key)\n    }\n\n    /// Construct a `PgAdvisoryLock` with a manually supplied key.\n    pub fn with_key(key: PgAdvisoryLockKey) -> Self {\n        Self {\n            key,\n            release_query: Arc::new(OnceLock::new()),\n        }\n    }\n\n    /// Returns the current key.\n    pub fn key(&self) -> &PgAdvisoryLockKey {\n        &self.key\n    }\n\n    // Why doesn't this use `Acquire`? Well, I tried it and got really useless errors\n    // about \"cannot project lifetimes to parent scope\".\n    //\n    // It has something to do with how lifetimes work on the `Acquire` trait, I couldn't\n    // be bothered to figure it out. Probably another issue with a lack of `async fn` in traits\n    // or lazy normalization.\n\n    /// Acquires an exclusive lock using `pg_advisory_lock()`, waiting until the lock is acquired.\n    ///\n    /// For a version that returns immediately instead of waiting, see [`Self::try_acquire()`].\n    ///\n    /// A connection-like type is required to execute the call. Allowed types include `PgConnection`,\n    /// `PoolConnection<Postgres>` and `Transaction<Postgres>`, as well as mutable references to\n    /// any of these.\n    ///\n    /// The returned guard queues a `pg_advisory_unlock()` call on the connection when dropped,\n    /// which will be executed the next time the connection is used, or when returned to a\n    /// [`PgPool`][crate::PgPool] in the case of `PoolConnection<Postgres>`.\n    ///\n    /// Postgres allows a single connection to acquire a given lock more than once without releasing\n    /// it first, so in that sense the lock is re-entrant. However, the number of unlock operations\n    /// must match the number of lock operations for the lock to actually be released.\n    ///\n    /// See [Postgres' documentation for the Advisory Lock Functions][advisory-funcs] for details.\n    ///\n    /// [advisory-funcs]: https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS\n    pub async fn acquire<C: AsMut<PgConnection>>(\n        &self,\n        mut conn: C,\n    ) -> Result<PgAdvisoryLockGuard<C>> {\n        match &self.key {\n            PgAdvisoryLockKey::BigInt(key) => {\n                crate::query::query(\"SELECT pg_advisory_lock($1)\")\n                    .bind(key)\n                    .execute(conn.as_mut())\n                    .await?;\n            }\n            PgAdvisoryLockKey::IntPair(key1, key2) => {\n                crate::query::query(\"SELECT pg_advisory_lock($1, $2)\")\n                    .bind(key1)\n                    .bind(key2)\n                    .execute(conn.as_mut())\n                    .await?;\n            }\n        }\n\n        Ok(PgAdvisoryLockGuard::new(self.clone(), conn))\n    }\n\n    /// Acquires an exclusive lock using `pg_try_advisory_lock()`, returning immediately\n    /// if the lock could not be acquired.\n    ///\n    /// For a version that waits until the lock is acquired, see [`Self::acquire()`].\n    ///\n    /// A connection-like type is required to execute the call. Allowed types include `PgConnection`,\n    /// `PoolConnection<Postgres>` and `Transaction<Postgres>`, as well as mutable references to\n    /// any of these. The connection is returned if the lock could not be acquired.\n    ///\n    /// The returned guard queues a `pg_advisory_unlock()` call on the connection when dropped,\n    /// which will be executed the next time the connection is used, or when returned to a\n    /// [`PgPool`][crate::PgPool] in the case of `PoolConnection<Postgres>`.\n    ///\n    /// Postgres allows a single connection to acquire a given lock more than once without releasing\n    /// it first, so in that sense the lock is re-entrant. However, the number of unlock operations\n    /// must match the number of lock operations for the lock to actually be released.\n    ///\n    /// See [Postgres' documentation for the Advisory Lock Functions][advisory-funcs] for details.\n    ///\n    /// [advisory-funcs]: https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS\n    pub async fn try_acquire<C: AsMut<PgConnection>>(\n        &self,\n        mut conn: C,\n    ) -> Result<Either<PgAdvisoryLockGuard<C>, C>> {\n        let locked: bool = match &self.key {\n            PgAdvisoryLockKey::BigInt(key) => {\n                crate::query_scalar::query_scalar(\"SELECT pg_try_advisory_lock($1)\")\n                    .bind(key)\n                    .fetch_one(conn.as_mut())\n                    .await?\n            }\n            PgAdvisoryLockKey::IntPair(key1, key2) => {\n                crate::query_scalar::query_scalar(\"SELECT pg_try_advisory_lock($1, $2)\")\n                    .bind(key1)\n                    .bind(key2)\n                    .fetch_one(conn.as_mut())\n                    .await?\n            }\n        };\n\n        if locked {\n            Ok(Either::Left(PgAdvisoryLockGuard::new(self.clone(), conn)))\n        } else {\n            Ok(Either::Right(conn))\n        }\n    }\n\n    /// Execute `pg_advisory_unlock()` for this lock's key on the given connection.\n    ///\n    /// This is used by [`PgAdvisoryLockGuard::release_now()`] and is also provided for manually\n    /// releasing the lock from connections returned by [`PgAdvisoryLockGuard::leak()`].\n    ///\n    /// An error should only be returned if there is something wrong with the connection,\n    /// in which case the lock will be automatically released by the connection closing anyway.\n    ///\n    /// The `boolean` value is that returned by `pg_advisory_lock()`. If it is `false`, it\n    /// indicates that the lock was not actually held by the given connection and that a warning\n    /// has been logged by the Postgres server.\n    pub async fn force_release<C: AsMut<PgConnection>>(&self, mut conn: C) -> Result<(C, bool)> {\n        let released: bool = match &self.key {\n            PgAdvisoryLockKey::BigInt(key) => {\n                crate::query_scalar::query_scalar(\"SELECT pg_advisory_unlock($1)\")\n                    .bind(key)\n                    .fetch_one(conn.as_mut())\n                    .await?\n            }\n            PgAdvisoryLockKey::IntPair(key1, key2) => {\n                crate::query_scalar::query_scalar(\"SELECT pg_advisory_unlock($1, $2)\")\n                    .bind(key1)\n                    .bind(key2)\n                    .fetch_one(conn.as_mut())\n                    .await?\n            }\n        };\n\n        Ok((conn, released))\n    }\n\n    fn get_release_query(&self) -> &str {\n        self.release_query.get_or_init(|| match &self.key {\n            PgAdvisoryLockKey::BigInt(key) => format!(\"SELECT pg_advisory_unlock({key})\"),\n            PgAdvisoryLockKey::IntPair(key1, key2) => {\n                format!(\"SELECT pg_advisory_unlock({key1}, {key2})\")\n            }\n        })\n    }\n}\n\nimpl PgAdvisoryLockKey {\n    /// Converts `Self::Bigint(bigint)` to `Some(bigint)` and all else to `None`.\n    pub fn as_bigint(&self) -> Option<i64> {\n        if let Self::BigInt(bigint) = self {\n            Some(*bigint)\n        } else {\n            None\n        }\n    }\n}\n\nconst NONE_ERR: &str = \"BUG: PgAdvisoryLockGuard.conn taken\";\n\nimpl<C: AsMut<PgConnection>> PgAdvisoryLockGuard<C> {\n    fn new(lock: PgAdvisoryLock, conn: C) -> Self {\n        PgAdvisoryLockGuard {\n            lock,\n            conn: Some(conn),\n        }\n    }\n\n    /// Immediately release the held advisory lock instead of when the connection is next used.\n    ///\n    /// An error should only be returned if there is something wrong with the connection,\n    /// in which case the lock will be automatically released by the connection closing anyway.\n    ///\n    /// If `pg_advisory_unlock()` returns `false`, a warning will be logged, both by SQLx as\n    /// well as the Postgres server. This would only happen if the lock was released without\n    /// using this guard, or the connection was swapped using [`std::mem::replace()`].\n    pub async fn release_now(mut self) -> Result<C> {\n        let (conn, released) = self\n            .lock\n            .force_release(self.conn.take().expect(NONE_ERR))\n            .await?;\n\n        if !released {\n            tracing::warn!(\n                lock = ?self.lock.key,\n                \"PgAdvisoryLockGuard: advisory lock was not held by the contained connection\",\n            );\n        }\n\n        Ok(conn)\n    }\n\n    /// Cancel the release of the advisory lock, keeping it held until the connection is closed.\n    ///\n    /// To manually release the lock later, see [`PgAdvisoryLock::force_release()`].\n    pub fn leak(mut self) -> C {\n        self.conn.take().expect(NONE_ERR)\n    }\n}\n\nimpl<C: AsMut<PgConnection> + AsRef<PgConnection>> Deref for PgAdvisoryLockGuard<C> {\n    type Target = PgConnection;\n\n    fn deref(&self) -> &Self::Target {\n        self.conn.as_ref().expect(NONE_ERR).as_ref()\n    }\n}\n\n/// Mutable access to the underlying connection is provided so it can still be used like normal,\n/// even allowing locks to be taken recursively.\n///\n/// However, replacing the connection with a different one using, e.g. [`std::mem::replace()`]\n/// is a logic error and will cause a warning to be logged by the PostgreSQL server when this\n/// guard attempts to release the lock.\nimpl<C: AsMut<PgConnection> + AsRef<PgConnection>> DerefMut for PgAdvisoryLockGuard<C> {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        self.conn.as_mut().expect(NONE_ERR).as_mut()\n    }\n}\n\nimpl<C: AsMut<PgConnection> + AsRef<PgConnection>> AsRef<PgConnection> for PgAdvisoryLockGuard<C> {\n    fn as_ref(&self) -> &PgConnection {\n        self.conn.as_ref().expect(NONE_ERR).as_ref()\n    }\n}\n\n/// Mutable access to the underlying connection is provided so it can still be used like normal,\n/// even allowing locks to be taken recursively.\n///\n/// However, replacing the connection with a different one using, e.g. [`std::mem::replace()`]\n/// is a logic error and will cause a warning to be logged by the PostgreSQL server when this\n/// guard attempts to release the lock.\nimpl<C: AsMut<PgConnection>> AsMut<PgConnection> for PgAdvisoryLockGuard<C> {\n    fn as_mut(&mut self) -> &mut PgConnection {\n        self.conn.as_mut().expect(NONE_ERR).as_mut()\n    }\n}\n\n/// Queues a `pg_advisory_unlock()` call on the wrapped connection which will be flushed\n/// to the server the next time it is used, or when it is returned to [`PgPool`][crate::PgPool]\n/// in the case of [`PoolConnection<Postgres>`][crate::pool::PoolConnection].\nimpl<C: AsMut<PgConnection>> Drop for PgAdvisoryLockGuard<C> {\n    fn drop(&mut self) {\n        if let Some(mut conn) = self.conn.take() {\n            // Queue a simple query message to execute next time the connection is used.\n            // The `async fn` versions can safely use the prepared statement protocol,\n            // but this is the safest way to queue a query to execute on the next opportunity.\n            conn.as_mut()\n                .queue_simple_query(self.lock.get_release_query())\n                .expect(\"BUG: PgAdvisoryLock::get_release_query() somehow too long for protocol\");\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/any.rs",
    "content": "use crate::{\n    Either, PgColumn, PgConnectOptions, PgConnection, PgQueryResult, PgRow, PgTransactionManager,\n    PgTypeInfo, Postgres,\n};\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::{stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt};\nuse sqlx_core::sql_str::SqlStr;\nuse std::{future, pin::pin};\n\nuse sqlx_core::any::{\n    AnyArguments, AnyColumn, AnyConnectOptions, AnyConnectionBackend, AnyQueryResult, AnyRow,\n    AnyStatement, AnyTypeInfo, AnyTypeInfoKind,\n};\n\nuse crate::type_info::PgType;\nuse sqlx_core::connection::Connection;\nuse sqlx_core::database::Database;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::ext::ustr::UStr;\nuse sqlx_core::transaction::TransactionManager;\n\nsqlx_core::declare_driver_with_optional_migrate!(DRIVER = Postgres);\n\nimpl AnyConnectionBackend for PgConnection {\n    fn name(&self) -> &str {\n        <Postgres as Database>::NAME\n    }\n\n    fn close(self: Box<Self>) -> BoxFuture<'static, sqlx_core::Result<()>> {\n        Connection::close(*self).boxed()\n    }\n\n    fn close_hard(self: Box<Self>) -> BoxFuture<'static, sqlx_core::Result<()>> {\n        Connection::close_hard(*self).boxed()\n    }\n\n    fn ping(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        Connection::ping(self).boxed()\n    }\n\n    fn begin(&mut self, statement: Option<SqlStr>) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        PgTransactionManager::begin(self, statement).boxed()\n    }\n\n    fn commit(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        PgTransactionManager::commit(self).boxed()\n    }\n\n    fn rollback(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        PgTransactionManager::rollback(self).boxed()\n    }\n\n    fn start_rollback(&mut self) {\n        PgTransactionManager::start_rollback(self)\n    }\n\n    fn get_transaction_depth(&self) -> usize {\n        PgTransactionManager::get_transaction_depth(self)\n    }\n\n    fn shrink_buffers(&mut self) {\n        Connection::shrink_buffers(self);\n    }\n\n    fn flush(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        Connection::flush(self).boxed()\n    }\n\n    fn should_flush(&self) -> bool {\n        Connection::should_flush(self)\n    }\n\n    #[cfg(feature = \"migrate\")]\n    fn as_migrate(\n        &mut self,\n    ) -> sqlx_core::Result<&mut (dyn sqlx_core::migrate::Migrate + Send + 'static)> {\n        Ok(self)\n    }\n\n    fn fetch_many(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxStream<sqlx_core::Result<Either<AnyQueryResult, AnyRow>>> {\n        let persistent = persistent && arguments.is_some();\n        let arguments = match arguments.map(AnyArguments::convert_into).transpose() {\n            Ok(arguments) => arguments,\n            Err(error) => {\n                return stream::once(future::ready(Err(sqlx_core::Error::Encode(error)))).boxed()\n            }\n        };\n\n        Box::pin(\n            self.run(query, arguments, persistent, None)\n                .try_flatten_stream()\n                .map(\n                    move |res: sqlx_core::Result<Either<PgQueryResult, PgRow>>| match res? {\n                        Either::Left(result) => Ok(Either::Left(map_result(result))),\n                        Either::Right(row) => Ok(Either::Right(AnyRow::try_from(&row)?)),\n                    },\n                ),\n        )\n    }\n\n    fn fetch_optional(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxFuture<sqlx_core::Result<Option<AnyRow>>> {\n        let persistent = persistent && arguments.is_some();\n        let arguments = arguments\n            .map(AnyArguments::convert_into)\n            .transpose()\n            .map_err(sqlx_core::Error::Encode);\n\n        Box::pin(async move {\n            let arguments = arguments?;\n            let mut stream = pin!(self.run(query, arguments, persistent, None).await?);\n\n            if let Some(Either::Right(row)) = stream.try_next().await? {\n                return Ok(Some(AnyRow::try_from(&row)?));\n            }\n\n            Ok(None)\n        })\n    }\n\n    fn prepare_with<'c, 'q: 'c>(\n        &'c mut self,\n        sql: SqlStr,\n        _parameters: &[AnyTypeInfo],\n    ) -> BoxFuture<'c, sqlx_core::Result<AnyStatement>> {\n        Box::pin(async move {\n            let statement = Executor::prepare_with(self, sql, &[]).await?;\n            let column_names = statement.metadata.column_names.clone();\n            AnyStatement::try_from_statement(statement, column_names)\n        })\n    }\n\n    #[cfg(feature = \"offline\")]\n    fn describe<'c>(\n        &mut self,\n        sql: SqlStr,\n    ) -> BoxFuture<'_, sqlx_core::Result<sqlx_core::describe::Describe<sqlx_core::any::Any>>> {\n        Box::pin(async move {\n            let describe = Executor::describe(self, sql).await?;\n\n            let columns = describe\n                .columns\n                .iter()\n                .map(AnyColumn::try_from)\n                .collect::<Result<Vec<_>, _>>()?;\n\n            let parameters = match describe.parameters {\n                Some(Either::Left(parameters)) => Some(Either::Left(\n                    parameters\n                        .iter()\n                        .enumerate()\n                        .map(|(i, type_info)| {\n                            AnyTypeInfo::try_from(type_info).map_err(|_| {\n                                sqlx_core::Error::AnyDriverError(\n                                    format!(\n                                        \"Any driver does not support type {type_info} of parameter {i}\"\n                                    )\n                                    .into(),\n                                )\n                            })\n                        })\n                        .collect::<Result<Vec<_>, _>>()?,\n                )),\n                Some(Either::Right(count)) => Some(Either::Right(count)),\n                None => None,\n            };\n\n            Ok(sqlx_core::describe::Describe {\n                columns,\n                parameters,\n                nullable: describe.nullable,\n            })\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a PgTypeInfo> for AnyTypeInfo {\n    type Error = sqlx_core::Error;\n\n    fn try_from(pg_type: &'a PgTypeInfo) -> Result<Self, Self::Error> {\n        Ok(AnyTypeInfo {\n            kind: match &pg_type.0 {\n                PgType::Bool => AnyTypeInfoKind::Bool,\n                PgType::Void => AnyTypeInfoKind::Null,\n                PgType::Int2 => AnyTypeInfoKind::SmallInt,\n                PgType::Int4 => AnyTypeInfoKind::Integer,\n                PgType::Int8 => AnyTypeInfoKind::BigInt,\n                PgType::Float4 => AnyTypeInfoKind::Real,\n                PgType::Float8 => AnyTypeInfoKind::Double,\n                PgType::Bytea => AnyTypeInfoKind::Blob,\n                PgType::Text | PgType::Varchar => AnyTypeInfoKind::Text,\n                PgType::DeclareWithName(UStr::Static(\"citext\")) => AnyTypeInfoKind::Text,\n                _ => {\n                    return Err(sqlx_core::Error::AnyDriverError(\n                        format!(\"Any driver does not support the Postgres type {pg_type:?}\").into(),\n                    ))\n                }\n            },\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a PgColumn> for AnyColumn {\n    type Error = sqlx_core::Error;\n\n    fn try_from(col: &'a PgColumn) -> Result<Self, Self::Error> {\n        let type_info =\n            AnyTypeInfo::try_from(&col.type_info).map_err(|e| sqlx_core::Error::ColumnDecode {\n                index: col.name.to_string(),\n                source: e.into(),\n            })?;\n\n        Ok(AnyColumn {\n            ordinal: col.ordinal,\n            name: col.name.clone(),\n            type_info,\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a PgRow> for AnyRow {\n    type Error = sqlx_core::Error;\n\n    fn try_from(row: &'a PgRow) -> Result<Self, Self::Error> {\n        AnyRow::map_from(row, row.metadata.column_names.clone())\n    }\n}\n\nimpl<'a> TryFrom<&'a AnyConnectOptions> for PgConnectOptions {\n    type Error = sqlx_core::Error;\n\n    fn try_from(value: &'a AnyConnectOptions) -> Result<Self, Self::Error> {\n        let mut opts = PgConnectOptions::parse_from_url(&value.database_url)?;\n        opts.log_settings = value.log_settings.clone();\n        Ok(opts)\n    }\n}\n\nfn map_result(res: PgQueryResult) -> AnyQueryResult {\n    AnyQueryResult {\n        rows_affected: res.rows_affected(),\n        last_insert_id: None,\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/arguments.rs",
    "content": "use std::fmt::{self, Write};\nuse std::ops::{Deref, DerefMut};\nuse std::sync::Arc;\n\nuse crate::encode::{Encode, IsNull};\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::types::Type;\nuse crate::{PgConnection, PgTypeInfo, Postgres};\n\nuse crate::type_info::PgArrayOf;\npub(crate) use sqlx_core::arguments::Arguments;\nuse sqlx_core::error::BoxDynError;\n\n// TODO: buf.patch(|| ...) is a poor name, can we think of a better name? Maybe `buf.lazy(||)` ?\n// TODO: Extend the patch system to support dynamic lengths\n//       Considerations:\n//          - The prefixed-len offset needs to be back-tracked and updated\n//          - message::Bind needs to take a &PgArguments and use a `write` method instead of\n//            referencing a buffer directly\n//          - The basic idea is that we write bytes for the buffer until we get somewhere\n//            that has a patch, we then apply the patch which should write to &mut Vec<u8>,\n//            backtrack and update the prefixed-len, then write until the next patch offset\n\n#[derive(Default, Debug, Clone)]\npub struct PgArgumentBuffer {\n    buffer: Vec<u8>,\n\n    // Number of arguments\n    count: usize,\n\n    // Whenever an `Encode` impl needs to defer some work until after we resolve parameter types\n    // it can use `patch`.\n    //\n    // This currently is only setup to be useful if there is a *fixed-size* slot that needs to be\n    // tweaked from the input type. However, that's the only use case we currently have.\n    patches: Vec<Patch>,\n\n    // Whenever an `Encode` impl encounters a `PgTypeInfo` object that does not have an OID\n    // It pushes a \"hole\" that must be patched later.\n    //\n    // The hole is a `usize` offset into the buffer with the type name that should be resolved\n    // This is done for Records and Arrays as the OID is needed well before we are in an async\n    // function and can just ask postgres.\n    //\n    type_holes: Vec<(usize, HoleKind)>, // Vec<{ offset, type_name }>\n}\n\n#[derive(Debug, Clone)]\nenum HoleKind {\n    Type { name: UStr },\n    Array(Arc<PgArrayOf>),\n}\n\n#[derive(Clone)]\nstruct Patch {\n    buf_offset: usize,\n    arg_index: usize,\n    #[allow(clippy::type_complexity)]\n    callback: Arc<dyn Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync>,\n}\n\nimpl fmt::Debug for Patch {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.debug_struct(\"Patch\")\n            .field(\"buf_offset\", &self.buf_offset)\n            .field(\"arg_index\", &self.arg_index)\n            .field(\"callback\", &\"<callback>\")\n            .finish()\n    }\n}\n\n/// Implementation of [`Arguments`] for PostgreSQL.\n#[derive(Default, Debug, Clone)]\npub struct PgArguments {\n    // Types of each bind parameter\n    pub(crate) types: Vec<PgTypeInfo>,\n\n    // Buffer of encoded bind parameters\n    pub(crate) buffer: PgArgumentBuffer,\n}\n\nimpl PgArguments {\n    pub(crate) fn add<'q, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'q, Postgres> + Type<Postgres>,\n    {\n        let type_info = value.produces().unwrap_or_else(T::type_info);\n\n        let buffer_snapshot = self.buffer.snapshot();\n\n        // encode the value into our buffer\n        if let Err(error) = self.buffer.encode(value) {\n            // reset the value buffer to its previous value if encoding failed,\n            // so we don't leave a half-encoded value behind\n            self.buffer.reset_to_snapshot(buffer_snapshot);\n            return Err(error);\n        };\n\n        // remember the type information for this value\n        self.types.push(type_info);\n        // increment the number of arguments we are tracking\n        self.buffer.count += 1;\n\n        Ok(())\n    }\n\n    // Apply patches\n    // This should only go out and ask postgres if we have not seen the type name yet\n    pub(crate) async fn apply_patches(\n        &mut self,\n        conn: &mut PgConnection,\n        parameters: &[PgTypeInfo],\n    ) -> Result<(), Error> {\n        let PgArgumentBuffer {\n            ref patches,\n            ref type_holes,\n            ref mut buffer,\n            ..\n        } = self.buffer;\n\n        for patch in patches {\n            let buf = &mut buffer[patch.buf_offset..];\n            let ty = &parameters[patch.arg_index];\n\n            (patch.callback)(buf, ty);\n        }\n\n        for (offset, kind) in type_holes {\n            let oid = match kind {\n                HoleKind::Type { name } => conn.fetch_type_id_by_name(name).await?,\n                HoleKind::Array(array) => conn.fetch_array_type_id(array).await?,\n            };\n            buffer[*offset..(*offset + 4)].copy_from_slice(&oid.0.to_be_bytes());\n        }\n\n        Ok(())\n    }\n}\n\nimpl Arguments for PgArguments {\n    type Database = Postgres;\n\n    fn reserve(&mut self, additional: usize, size: usize) {\n        self.types.reserve(additional);\n        self.buffer.reserve(size);\n    }\n\n    fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'t, Self::Database> + Type<Self::Database>,\n    {\n        self.add(value)\n    }\n\n    fn format_placeholder<W: Write>(&self, writer: &mut W) -> fmt::Result {\n        write!(writer, \"${}\", self.buffer.count)\n    }\n\n    #[inline(always)]\n    fn len(&self) -> usize {\n        self.buffer.count\n    }\n}\n\nimpl PgArgumentBuffer {\n    pub(crate) fn encode<'q, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'q, Postgres>,\n    {\n        // Won't catch everything but is a good sanity check\n        value_size_int4_checked(value.size_hint())?;\n\n        // reserve space to write the prefixed length of the value\n        let offset = self.len();\n\n        self.extend(&[0; 4]);\n\n        // encode the value into our buffer\n        let len = if let IsNull::No = value.encode(self)? {\n            // Ensure that the value size does not overflow i32\n            value_size_int4_checked(self.len() - offset - 4)?\n        } else {\n            // Write a -1 to indicate NULL\n            // NOTE: It is illegal for [encode] to write any data\n            debug_assert_eq!(self.len(), offset + 4);\n            -1_i32\n        };\n\n        // write the len to the beginning of the value\n        // (offset + 4) cannot overflow because it would have failed at `self.extend()`.\n        self[offset..(offset + 4)].copy_from_slice(&len.to_be_bytes());\n\n        Ok(())\n    }\n\n    // Adds a callback to be invoked later when we know the parameter type\n    #[allow(dead_code)]\n    pub(crate) fn patch<F>(&mut self, callback: F)\n    where\n        F: Fn(&mut [u8], &PgTypeInfo) + 'static + Send + Sync,\n    {\n        let offset = self.len();\n        let arg_index = self.count;\n\n        self.patches.push(Patch {\n            buf_offset: offset,\n            arg_index,\n            callback: Arc::new(callback),\n        });\n    }\n\n    // Extends the inner buffer by enough space to have an OID\n    // Remembers where the OID goes and type name for the OID\n    pub(crate) fn patch_type_by_name(&mut self, type_name: &UStr) {\n        let offset = self.len();\n\n        self.extend_from_slice(&0_u32.to_be_bytes());\n        self.type_holes.push((\n            offset,\n            HoleKind::Type {\n                name: type_name.clone(),\n            },\n        ));\n    }\n\n    pub(crate) fn patch_array_type(&mut self, array: Arc<PgArrayOf>) {\n        let offset = self.len();\n\n        self.extend_from_slice(&0_u32.to_be_bytes());\n        self.type_holes.push((offset, HoleKind::Array(array)));\n    }\n\n    fn snapshot(&self) -> PgArgumentBufferSnapshot {\n        let Self {\n            buffer,\n            count,\n            patches,\n            type_holes,\n        } = self;\n\n        PgArgumentBufferSnapshot {\n            buffer_length: buffer.len(),\n            count: *count,\n            patches_length: patches.len(),\n            type_holes_length: type_holes.len(),\n        }\n    }\n\n    fn reset_to_snapshot(\n        &mut self,\n        PgArgumentBufferSnapshot {\n            buffer_length,\n            count,\n            patches_length,\n            type_holes_length,\n        }: PgArgumentBufferSnapshot,\n    ) {\n        self.buffer.truncate(buffer_length);\n        self.count = count;\n        self.patches.truncate(patches_length);\n        self.type_holes.truncate(type_holes_length);\n    }\n}\n\nstruct PgArgumentBufferSnapshot {\n    buffer_length: usize,\n    count: usize,\n    patches_length: usize,\n    type_holes_length: usize,\n}\n\nimpl Deref for PgArgumentBuffer {\n    type Target = Vec<u8>;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        &self.buffer\n    }\n}\n\nimpl DerefMut for PgArgumentBuffer {\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.buffer\n    }\n}\n\npub(crate) fn value_size_int4_checked(size: usize) -> Result<i32, String> {\n    i32::try_from(size).map_err(|_| {\n        format!(\n            \"value size would overflow in the binary protocol encoding: {size} > {}\",\n            i32::MAX\n        )\n    })\n}\n"
  },
  {
    "path": "sqlx-postgres/src/bind_iter.rs",
    "content": "use crate::{type_info::PgType, PgArgumentBuffer, PgHasArrayType, PgTypeInfo, Postgres};\nuse core::cell::Cell;\nuse sqlx_core::{\n    database::Database,\n    encode::{Encode, IsNull},\n    error::BoxDynError,\n    types::Type,\n};\n\n// not exported but pub because it is used in the extension trait\npub struct PgBindIter<I>(Cell<Option<I>>);\n\n/// Iterator extension trait enabling iterators to encode arrays in Postgres.\n///\n/// Because of the blanket impl of `PgHasArrayType` for all references\n/// we can borrow instead of needing to clone or copy in the iterators\n/// and it still works\n///\n/// Previously, 3 separate arrays would be needed in this example which\n/// requires iterating 3 times to collect items into the array and then\n/// iterating over them again to encode.\n///\n/// This now requires only iterating over the array once for each field\n/// while using less memory giving both speed and memory usage improvements\n/// along with allowing much more flexibility in the underlying collection.\n///\n/// ```rust,no_run\n/// # async fn test_bind_iter() -> Result<(), sqlx::error::BoxDynError> {\n/// # use sqlx::types::chrono::{DateTime, Utc};\n/// # use sqlx::Connection;\n/// # fn people() -> &'static [Person] {\n/// #   &[]\n/// # }\n/// # let mut conn = <sqlx::Postgres as sqlx::Database>::Connection::connect(\"dummyurl\").await?;\n/// use sqlx::postgres::PgBindIterExt;\n///\n/// #[derive(sqlx::FromRow)]\n/// struct Person {\n///     id: i64,\n///     name: String,\n///     birthdate: DateTime<Utc>,\n/// }\n///\n/// # let people: &[Person] = people();\n/// sqlx::query(\"insert into person(id, name, birthdate) select * from unnest($1, $2, $3)\")\n///     .bind(people.iter().map(|p| p.id).bind_iter())\n///     .bind(people.iter().map(|p| &p.name).bind_iter())\n///     .bind(people.iter().map(|p| &p.birthdate).bind_iter())\n///     .execute(&mut conn)\n///     .await?;\n///\n/// # Ok(())\n/// # }\n/// ```\npub trait PgBindIterExt: Iterator + Sized {\n    fn bind_iter(self) -> PgBindIter<Self>;\n}\n\nimpl<I: Iterator + Sized> PgBindIterExt for I {\n    fn bind_iter(self) -> PgBindIter<I> {\n        PgBindIter(Cell::new(Some(self)))\n    }\n}\n\nimpl<I> Type<Postgres> for PgBindIter<I>\nwhere\n    I: Iterator,\n    <I as Iterator>::Item: Type<Postgres> + PgHasArrayType,\n{\n    fn type_info() -> <Postgres as Database>::TypeInfo {\n        <I as Iterator>::Item::array_type_info()\n    }\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        <I as Iterator>::Item::array_compatible(ty)\n    }\n}\n\nimpl<'q, I> PgBindIter<I>\nwhere\n    I: Iterator,\n    <I as Iterator>::Item: Type<Postgres> + Encode<'q, Postgres>,\n{\n    fn encode_inner(\n        // need ownership to iterate\n        mut iter: I,\n        buf: &mut PgArgumentBuffer,\n    ) -> Result<IsNull, BoxDynError> {\n        let lower_size_hint = iter.size_hint().0;\n        let first = iter.next();\n        let type_info = first\n            .as_ref()\n            .and_then(Encode::produces)\n            .unwrap_or_else(<I as Iterator>::Item::type_info);\n\n        buf.extend(&1_i32.to_be_bytes()); // number of dimensions\n        buf.extend(&0_i32.to_be_bytes()); // flags\n\n        match type_info.0 {\n            PgType::DeclareWithName(name) => buf.patch_type_by_name(&name),\n            PgType::DeclareArrayOf(array) => buf.patch_array_type(array),\n\n            ty => {\n                buf.extend(&ty.oid().0.to_be_bytes());\n            }\n        }\n\n        let len_start = buf.len();\n        buf.extend(0_i32.to_be_bytes()); // len (unknown so far)\n        buf.extend(1_i32.to_be_bytes()); // lower bound\n\n        match first {\n            Some(first) => buf.encode(first)?,\n            None => return Ok(IsNull::No),\n        }\n\n        let mut count = 1_i32;\n        const MAX: usize = i32::MAX as usize - 1;\n\n        for value in (&mut iter).take(MAX) {\n            buf.encode(value)?;\n            count += 1;\n        }\n\n        const OVERFLOW: usize = i32::MAX as usize + 1;\n        if iter.next().is_some() {\n            let iter_size = std::cmp::max(lower_size_hint, OVERFLOW);\n            return Err(format!(\"encoded iterator is too large for Postgres: {iter_size}\").into());\n        }\n\n        // set the length now that we know what it is.\n        buf[len_start..(len_start + 4)].copy_from_slice(&count.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'q, I> Encode<'q, Postgres> for PgBindIter<I>\nwhere\n    I: Iterator,\n    <I as Iterator>::Item: Type<Postgres> + Encode<'q, Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        Self::encode_inner(self.0.take().expect(\"PgBindIter is only used once\"), buf)\n    }\n    fn encode(self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError>\n    where\n        Self: Sized,\n    {\n        Self::encode_inner(\n            self.0.into_inner().expect(\"PgBindIter is only used once\"),\n            buf,\n        )\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/column.rs",
    "content": "use crate::ext::ustr::UStr;\nuse crate::{PgTypeInfo, Postgres};\n\nuse sqlx_core::column::ColumnOrigin;\npub(crate) use sqlx_core::column::{Column, ColumnIndex};\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct PgColumn {\n    pub(crate) ordinal: usize,\n    pub(crate) name: UStr,\n    pub(crate) type_info: PgTypeInfo,\n\n    #[cfg_attr(feature = \"offline\", serde(default))]\n    pub(crate) origin: ColumnOrigin,\n\n    #[cfg_attr(feature = \"offline\", serde(skip))]\n    pub(crate) relation_id: Option<crate::types::Oid>,\n    #[cfg_attr(feature = \"offline\", serde(skip))]\n    pub(crate) relation_attribute_no: Option<i16>,\n}\n\nimpl PgColumn {\n    /// Returns the OID of the table this column is from, if applicable.\n    ///\n    /// This will be `None` if the column is the result of an expression.\n    ///\n    /// Corresponds to column `attrelid` of the `pg_catalog.pg_attribute` table:\n    /// <https://www.postgresql.org/docs/current/catalog-pg-attribute.html>\n    pub fn relation_id(&self) -> Option<crate::types::Oid> {\n        self.relation_id\n    }\n\n    /// Returns the 1-based index of this column in its parent table, if applicable.\n    ///\n    /// This will be `None` if the column is the result of an expression.\n    ///\n    /// Corresponds to column `attnum` of the `pg_catalog.pg_attribute` table:\n    /// <https://www.postgresql.org/docs/current/catalog-pg-attribute.html>\n    pub fn relation_attribute_no(&self) -> Option<i16> {\n        self.relation_attribute_no\n    }\n}\n\nimpl Column for PgColumn {\n    type Database = Postgres;\n\n    fn ordinal(&self) -> usize {\n        self.ordinal\n    }\n\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn type_info(&self) -> &PgTypeInfo {\n        &self.type_info\n    }\n\n    fn origin(&self) -> ColumnOrigin {\n        self.origin.clone()\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/describe.rs",
    "content": "use crate::error::Error;\nuse crate::io::StatementId;\nuse crate::query_as::query_as;\nuse crate::statement::PgStatementMetadata;\nuse crate::types::Json;\nuse crate::PgConnection;\nuse smallvec::SmallVec;\nuse sqlx_core::query_builder::QueryBuilder;\nuse sqlx_core::sql_str::AssertSqlSafe;\n\nimpl PgConnection {\n    /// Check whether EXPLAIN statements are supported by the current connection\n    fn is_explain_available(&self) -> bool {\n        let parameter_statuses = &self.inner.stream.parameter_statuses;\n        let is_cockroachdb = parameter_statuses.contains_key(\"crdb_version\");\n        let is_materialize = parameter_statuses.contains_key(\"mz_version\");\n        let is_questdb = parameter_statuses.contains_key(\"questdb_version\");\n        !is_cockroachdb && !is_materialize && !is_questdb\n    }\n\n    pub(crate) async fn get_nullable_for_columns(\n        &mut self,\n        stmt_id: StatementId,\n        meta: &PgStatementMetadata,\n    ) -> Result<Vec<Option<bool>>, Error> {\n        if meta.columns.is_empty() {\n            return Ok(vec![]);\n        }\n\n        if meta.columns.len() * 3 > 65535 {\n            tracing::debug!(\n                ?stmt_id,\n                num_columns = meta.columns.len(),\n                \"number of columns in query is too large to pull nullability for\"\n            );\n        }\n\n        // Query for NOT NULL constraints for each column in the query.\n        //\n        // This will include columns that don't have a `relation_id` (are not from a table);\n        // assuming those are a minority of columns, it's less code to _not_ work around it\n        // and just let Postgres return `NULL`.\n        //\n        // Use `UNION ALL` syntax instead of `VALUES` due to frequent lack of\n        // support for `VALUES` in pgwire supported databases.\n        let mut nullable_query = QueryBuilder::new(\"SELECT NOT attnotnull FROM ( \");\n        let mut separated = nullable_query.separated(\"UNION ALL \");\n\n        let mut column_iter = meta.columns.iter().zip(0i32..);\n        if let Some((column, i)) = column_iter.next() {\n            separated.push(\"( SELECT \");\n            separated\n                .push_bind_unseparated(i)\n                .push_unseparated(\"::int4 AS idx, \");\n            separated\n                .push_bind_unseparated(column.relation_id)\n                .push_unseparated(\"::int4 AS table_id, \");\n            separated\n                .push_bind_unseparated(column.relation_attribute_no)\n                .push_unseparated(\"::int2 AS col_idx ) \");\n        }\n\n        for (column, i) in column_iter {\n            separated.push(\"( SELECT \");\n            separated\n                .push_bind_unseparated(i)\n                .push_unseparated(\"::int4, \");\n            separated\n                .push_bind_unseparated(column.relation_id)\n                .push_unseparated(\"::int4, \");\n            separated\n                .push_bind_unseparated(column.relation_attribute_no)\n                .push_unseparated(\"::int2 ) \");\n        }\n\n        nullable_query.push(\n            \") AS col LEFT JOIN pg_catalog.pg_attribute \\\n                ON table_id IS NOT NULL \\\n               AND attrelid = table_id \\\n               AND attnum = col_idx \\\n            ORDER BY idx\",\n        );\n\n        let mut nullables: Vec<Option<bool>> = nullable_query\n            .build_query_scalar()\n            .fetch_all(&mut *self)\n            .await\n            .map_err(|e| {\n                err_protocol!(\n                    \"error from nullables query: {e}; query: {:?}\",\n                    nullable_query.sql()\n                )\n            })?;\n\n        // If the server doesn't support EXPLAIN statements, skip this step (#1248).\n        if self.is_explain_available() {\n            // patch up our null inference with data from EXPLAIN\n            let nullable_patch = self\n                .nullables_from_explain(stmt_id, meta.parameters.len())\n                .await?;\n\n            for (nullable, patch) in nullables.iter_mut().zip(nullable_patch) {\n                *nullable = patch.or(*nullable);\n            }\n        }\n\n        Ok(nullables)\n    }\n\n    /// Infer nullability for columns of this statement using EXPLAIN VERBOSE.\n    ///\n    /// This currently only marks columns that are on the inner half of an outer join\n    /// and returns `None` for all others.\n    async fn nullables_from_explain(\n        &mut self,\n        stmt_id: StatementId,\n        params_len: usize,\n    ) -> Result<Vec<Option<bool>>, Error> {\n        let stmt_id_display = stmt_id\n            .display()\n            .ok_or_else(|| err_protocol!(\"cannot EXPLAIN unnamed statement: {stmt_id:?}\"))?;\n\n        let mut explain = format!(\"EXPLAIN (VERBOSE, FORMAT JSON) EXECUTE {stmt_id_display}\");\n        let mut comma = false;\n\n        if params_len > 0 {\n            explain += \"(\";\n\n            // fill the arguments list with NULL, which should theoretically be valid\n            for _ in 0..params_len {\n                if comma {\n                    explain += \", \";\n                }\n\n                explain += \"NULL\";\n                comma = true;\n            }\n\n            explain += \")\";\n        }\n\n        let (Json(explains),): (Json<SmallVec<[Explain; 1]>>,) =\n            query_as(AssertSqlSafe(explain)).fetch_one(self).await?;\n\n        let mut nullables = Vec::new();\n\n        if let Some(Explain::Plan {\n            plan:\n                plan @ Plan {\n                    output: Some(ref outputs),\n                    ..\n                },\n        }) = explains.first()\n        {\n            nullables.resize(outputs.len(), None);\n            visit_plan(plan, outputs, &mut nullables);\n        }\n\n        Ok(nullables)\n    }\n}\n\nfn visit_plan(plan: &Plan, outputs: &[String], nullables: &mut Vec<Option<bool>>) {\n    if let Some(plan_outputs) = &plan.output {\n        // all outputs of a Full Join must be marked nullable\n        // otherwise, all outputs of the inner half of an outer join must be marked nullable\n        if plan.join_type.as_deref() == Some(\"Full\")\n            || plan.parent_relation.as_deref() == Some(\"Inner\")\n        {\n            for output in plan_outputs {\n                if let Some(i) = outputs.iter().position(|o| o == output) {\n                    // N.B. this may produce false positives but those don't cause runtime errors\n                    nullables[i] = Some(true);\n                }\n            }\n        }\n    }\n\n    if let Some(plans) = &plan.plans {\n        if let Some(\"Left\") | Some(\"Right\") = plan.join_type.as_deref() {\n            for plan in plans {\n                visit_plan(plan, outputs, nullables);\n            }\n        }\n    }\n}\n\n#[derive(serde::Deserialize, Debug)]\n#[serde(untagged)]\nenum Explain {\n    // NOTE: the returned JSON may not contain a `plan` field, for example, with `CALL` statements:\n    // https://github.com/launchbadge/sqlx/issues/1449\n    //\n    // In this case, we should just fall back to assuming all is nullable.\n    //\n    // It may also contain additional fields we don't care about, which should not break parsing:\n    // https://github.com/launchbadge/sqlx/issues/2587\n    // https://github.com/launchbadge/sqlx/issues/2622\n    Plan {\n        #[serde(rename = \"Plan\")]\n        plan: Plan,\n    },\n\n    // This ensures that parsing never technically fails.\n    //\n    // We don't want to specifically expect `\"Utility Statement\"` because there might be other cases\n    // and we don't care unless it contains a query plan anyway.\n    Other(serde::de::IgnoredAny),\n}\n\n#[derive(serde::Deserialize, Debug)]\nstruct Plan {\n    #[serde(rename = \"Join Type\")]\n    join_type: Option<String>,\n    #[serde(rename = \"Parent Relationship\")]\n    parent_relation: Option<String>,\n    #[serde(rename = \"Output\")]\n    output: Option<Vec<String>>,\n    #[serde(rename = \"Plans\")]\n    plans: Option<Vec<Plan>>,\n}\n\n#[test]\nfn explain_parsing() {\n    let normal_plan = r#\"[\n   {\n     \"Plan\": {\n       \"Node Type\": \"Result\",\n       \"Parallel Aware\": false,\n       \"Async Capable\": false,\n       \"Startup Cost\": 0.00,\n       \"Total Cost\": 0.01,\n       \"Plan Rows\": 1,\n       \"Plan Width\": 4,\n       \"Output\": [\"1\"]\n     }\n   }\n]\"#;\n\n    // https://github.com/launchbadge/sqlx/issues/2622\n    let extra_field = r#\"[\n   {                                        \n     \"Plan\": {                              \n       \"Node Type\": \"Result\",               \n       \"Parallel Aware\": false,             \n       \"Async Capable\": false,              \n       \"Startup Cost\": 0.00,                \n       \"Total Cost\": 0.01,                  \n       \"Plan Rows\": 1,                      \n       \"Plan Width\": 4,                     \n       \"Output\": [\"1\"]                      \n     },                                     \n     \"Query Identifier\": 1147616880456321454\n   }                                        \n]\"#;\n\n    // https://github.com/launchbadge/sqlx/issues/1449\n    let utility_statement = r#\"[\"Utility Statement\"]\"#;\n\n    let normal_plan_parsed = serde_json::from_str::<[Explain; 1]>(normal_plan).unwrap();\n    let extra_field_parsed = serde_json::from_str::<[Explain; 1]>(extra_field).unwrap();\n    let utility_statement_parsed = serde_json::from_str::<[Explain; 1]>(utility_statement).unwrap();\n\n    assert!(\n        matches!(normal_plan_parsed, [Explain::Plan { plan: Plan { .. } }]),\n        \"unexpected parse from {normal_plan:?}: {normal_plan_parsed:?}\"\n    );\n\n    assert!(\n        matches!(extra_field_parsed, [Explain::Plan { plan: Plan { .. } }]),\n        \"unexpected parse from {extra_field:?}: {extra_field_parsed:?}\"\n    );\n\n    assert!(\n        matches!(utility_statement_parsed, [Explain::Other(_)]),\n        \"unexpected parse from {utility_statement:?}: {utility_statement_parsed:?}\"\n    )\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/establish.rs",
    "content": "use crate::HashMap;\n\nuse crate::common::StatementCache;\nuse crate::connection::{sasl, stream::PgStream};\nuse crate::error::Error;\nuse crate::io::StatementId;\nuse crate::message::{\n    Authentication, BackendKeyData, BackendMessageFormat, Password, ReadyForQuery, Startup,\n};\nuse crate::{PgConnectOptions, PgConnection};\n\nuse super::PgConnectionInner;\n\n// https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.3\n// https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.11\n\nimpl PgConnection {\n    pub(crate) async fn establish(options: &PgConnectOptions) -> Result<Self, Error> {\n        // Upgrade to TLS if we were asked to and the server supports it\n        let mut stream = PgStream::connect(options).await?;\n\n        // To begin a session, a frontend opens a connection to the server\n        // and sends a startup message.\n\n        let mut params = vec![\n            // Sets the display format for date and time values,\n            // as well as the rules for interpreting ambiguous date input values.\n            (\"DateStyle\", \"ISO, MDY\"),\n            // Sets the client-side encoding (character set).\n            // <https://www.postgresql.org/docs/devel/multibyte.html#MULTIBYTE-CHARSET-SUPPORTED>\n            (\"client_encoding\", \"UTF8\"),\n            // Sets the time zone for displaying and interpreting time stamps.\n            (\"TimeZone\", \"UTC\"),\n        ];\n\n        if let Some(ref extra_float_digits) = options.extra_float_digits {\n            params.push((\"extra_float_digits\", extra_float_digits));\n        }\n\n        if let Some(ref application_name) = options.application_name {\n            params.push((\"application_name\", application_name));\n        }\n\n        if let Some(ref options) = options.options {\n            params.push((\"options\", options));\n        }\n\n        stream.write(Startup {\n            username: Some(&options.username),\n            database: options.database.as_deref(),\n            params: &params,\n        })?;\n\n        stream.flush().await?;\n\n        // The server then uses this information and the contents of\n        // its configuration files (such as pg_hba.conf) to determine whether the connection is\n        // provisionally acceptable, and what additional\n        // authentication is required (if any).\n\n        let mut process_id = 0;\n        let mut secret_key = 0;\n        let transaction_status;\n\n        loop {\n            let message = stream.recv().await?;\n            match message.format {\n                BackendMessageFormat::Authentication => match message.decode()? {\n                    Authentication::Ok => {\n                        // the authentication exchange is successfully completed\n                        // do nothing; no more information is required to continue\n                    }\n\n                    Authentication::CleartextPassword => {\n                        // The frontend must now send a [PasswordMessage] containing the\n                        // password in clear-text form.\n\n                        stream\n                            .send(Password::Cleartext(\n                                options.password.as_deref().unwrap_or_default(),\n                            ))\n                            .await?;\n                    }\n\n                    Authentication::Md5Password(body) => {\n                        // The frontend must now send a [PasswordMessage] containing the\n                        // password (with user name) encrypted via MD5, then encrypted again\n                        // using the 4-byte random salt specified in the\n                        // [AuthenticationMD5Password] message.\n\n                        stream\n                            .send(Password::Md5 {\n                                username: &options.username,\n                                password: options.password.as_deref().unwrap_or_default(),\n                                salt: body.salt,\n                            })\n                            .await?;\n                    }\n\n                    Authentication::Sasl(body) => {\n                        sasl::authenticate(&mut stream, options, body).await?;\n                    }\n\n                    method => {\n                        return Err(err_protocol!(\n                            \"unsupported authentication method: {:?}\",\n                            method\n                        ));\n                    }\n                },\n\n                BackendMessageFormat::BackendKeyData => {\n                    // provides secret-key data that the frontend must save if it wants to be\n                    // able to issue cancel requests later\n\n                    let data: BackendKeyData = message.decode()?;\n\n                    process_id = data.process_id;\n                    secret_key = data.secret_key;\n                }\n\n                BackendMessageFormat::ReadyForQuery => {\n                    // start-up is completed. The frontend can now issue commands\n                    transaction_status = message.decode::<ReadyForQuery>()?.transaction_status;\n\n                    break;\n                }\n\n                _ => {\n                    return Err(err_protocol!(\n                        \"establish: unexpected message: {:?}\",\n                        message.format\n                    ))\n                }\n            }\n        }\n\n        Ok(PgConnection {\n            inner: Box::new(PgConnectionInner {\n                stream,\n                process_id,\n                secret_key,\n                transaction_status,\n                transaction_depth: 0,\n                pending_ready_for_query_count: 0,\n                next_statement_id: StatementId::NAMED_START,\n                cache_statement: StatementCache::new(options.statement_cache_capacity),\n                cache_type_oid: HashMap::new(),\n                cache_type_info: HashMap::new(),\n                cache_elem_type_to_array: HashMap::new(),\n                cache_table_to_column_names: HashMap::new(),\n                log_settings: options.log_settings.clone(),\n            }),\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/executor.rs",
    "content": "use crate::error::Error;\nuse crate::executor::{Execute, Executor};\nuse crate::io::{PortalId, StatementId};\nuse crate::logger::QueryLogger;\nuse crate::message::{\n    self, BackendMessageFormat, Bind, Close, CommandComplete, DataRow, ParameterDescription, Parse,\n    ParseComplete, Query, RowDescription,\n};\nuse crate::statement::PgStatementMetadata;\nuse crate::{\n    statement::PgStatement, PgArguments, PgConnection, PgQueryResult, PgRow, PgTypeInfo,\n    PgValueFormat, Postgres,\n};\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_core::Stream;\nuse futures_util::TryStreamExt;\nuse sqlx_core::arguments::Arguments;\nuse sqlx_core::sql_str::SqlStr;\nuse sqlx_core::Either;\nuse std::{pin::pin, sync::Arc};\n\nasync fn prepare(\n    conn: &mut PgConnection,\n    sql: &str,\n    parameters: &[PgTypeInfo],\n    metadata: Option<Arc<PgStatementMetadata>>,\n    persistent: bool,\n    fetch_column_origin: bool,\n) -> Result<(StatementId, Arc<PgStatementMetadata>), Error> {\n    let id = if persistent {\n        let id = conn.inner.next_statement_id;\n        conn.inner.next_statement_id = id.next();\n        id\n    } else {\n        StatementId::UNNAMED\n    };\n\n    // build a list of type OIDs to send to the database in the PARSE command\n    // we have not yet started the query sequence, so we are *safe* to cleanly make\n    // additional queries here to get any missing OIDs\n\n    let mut param_types = Vec::with_capacity(parameters.len());\n\n    for ty in parameters {\n        param_types.push(conn.resolve_type_id(&ty.0).await?);\n    }\n\n    // flush and wait until we are re-ready\n    conn.wait_until_ready().await?;\n\n    // next we send the PARSE command to the server\n    conn.inner.stream.write_msg(Parse {\n        param_types: &param_types,\n        query: sql,\n        statement: id,\n    })?;\n\n    if metadata.is_none() {\n        // get the statement columns and parameters\n        conn.inner\n            .stream\n            .write_msg(message::Describe::Statement(id))?;\n    }\n\n    // we ask for the server to immediately send us the result of the PARSE command\n    conn.write_sync();\n    conn.inner.stream.flush().await?;\n\n    // indicates that the SQL query string is now successfully parsed and has semantic validity\n    conn.inner.stream.recv_expect::<ParseComplete>().await?;\n\n    let metadata = if let Some(metadata) = metadata {\n        // each SYNC produces one READY FOR QUERY\n        conn.recv_ready_for_query().await?;\n\n        // we already have metadata\n        metadata\n    } else {\n        let parameters = recv_desc_params(conn).await?;\n\n        let rows = recv_desc_rows(conn).await?;\n\n        // each SYNC produces one READY FOR QUERY\n        conn.recv_ready_for_query().await?;\n\n        let parameters = conn.handle_parameter_description(parameters).await?;\n\n        let (columns, column_names) = conn\n            .handle_row_description(rows, true, fetch_column_origin)\n            .await?;\n\n        // ensure that if we did fetch custom data, we wait until we are fully ready before\n        // continuing\n        conn.wait_until_ready().await?;\n\n        Arc::new(PgStatementMetadata {\n            parameters,\n            columns,\n            column_names: Arc::new(column_names),\n        })\n    };\n\n    Ok((id, metadata))\n}\n\nasync fn recv_desc_params(conn: &mut PgConnection) -> Result<ParameterDescription, Error> {\n    conn.inner.stream.recv_expect().await\n}\n\nasync fn recv_desc_rows(conn: &mut PgConnection) -> Result<Option<RowDescription>, Error> {\n    let rows: Option<RowDescription> = match conn.inner.stream.recv().await? {\n        // describes the rows that will be returned when the statement is eventually executed\n        message if message.format == BackendMessageFormat::RowDescription => {\n            Some(message.decode()?)\n        }\n\n        // no data would be returned if this statement was executed\n        message if message.format == BackendMessageFormat::NoData => None,\n\n        message => {\n            return Err(err_protocol!(\n                \"expecting RowDescription or NoData but received {:?}\",\n                message.format\n            ));\n        }\n    };\n\n    Ok(rows)\n}\n\nimpl PgConnection {\n    // wait for CloseComplete to indicate a statement was closed\n    pub(super) async fn wait_for_close_complete(&mut self, mut count: usize) -> Result<(), Error> {\n        // we need to wait for the [CloseComplete] to be returned from the server\n        while count > 0 {\n            match self.inner.stream.recv().await? {\n                message if message.format == BackendMessageFormat::PortalSuspended => {\n                    // there was an open portal\n                    // this can happen if the last time a statement was used it was not fully executed\n                }\n\n                message if message.format == BackendMessageFormat::CloseComplete => {\n                    // successfully closed the statement (and freed up the server resources)\n                    count -= 1;\n                }\n\n                message => {\n                    return Err(err_protocol!(\n                        \"expecting PortalSuspended or CloseComplete but received {:?}\",\n                        message.format\n                    ));\n                }\n            }\n        }\n\n        Ok(())\n    }\n\n    #[inline(always)]\n    pub(crate) fn write_sync(&mut self) {\n        self.inner\n            .stream\n            .write_msg(message::Sync)\n            .expect(\"BUG: Sync should not be too big for protocol\");\n\n        // all SYNC messages will return a ReadyForQuery\n        self.inner.pending_ready_for_query_count += 1;\n    }\n\n    async fn get_or_prepare(\n        &mut self,\n        sql: &str,\n        parameters: &[PgTypeInfo],\n        persistent: bool,\n        // optional metadata that was provided by the user, this means they are reusing\n        // a statement object\n        metadata: Option<Arc<PgStatementMetadata>>,\n        fetch_column_origin: bool,\n    ) -> Result<(StatementId, Arc<PgStatementMetadata>), Error> {\n        if let Some(statement) = self.inner.cache_statement.get_mut(sql) {\n            return Ok((*statement).clone());\n        }\n\n        let statement = prepare(\n            self,\n            sql,\n            parameters,\n            metadata,\n            persistent,\n            fetch_column_origin,\n        )\n        .await?;\n\n        if persistent && self.inner.cache_statement.is_enabled() {\n            if let Some((id, _)) = self.inner.cache_statement.insert(sql, statement.clone()) {\n                self.inner.stream.write_msg(Close::Statement(id))?;\n                self.write_sync();\n\n                self.inner.stream.flush().await?;\n\n                self.wait_for_close_complete(1).await?;\n                self.recv_ready_for_query().await?;\n            }\n        }\n\n        Ok(statement)\n    }\n\n    pub(crate) async fn run<'e, 'c: 'e, 'q: 'e>(\n        &'c mut self,\n        query: SqlStr,\n        arguments: Option<PgArguments>,\n        persistent: bool,\n        metadata_opt: Option<Arc<PgStatementMetadata>>,\n    ) -> Result<impl Stream<Item = Result<Either<PgQueryResult, PgRow>, Error>> + 'e, Error> {\n        let mut logger = QueryLogger::new(query, self.inner.log_settings.clone());\n        let sql = logger.sql().as_str();\n\n        // before we continue, wait until we are \"ready\" to accept more queries\n        self.wait_until_ready().await?;\n\n        let mut metadata: Arc<PgStatementMetadata>;\n\n        let format = if let Some(mut arguments) = arguments {\n            // Check this before we write anything to the stream.\n            //\n            // Note: Postgres actually interprets this value as unsigned,\n            // making the max number of parameters 65535, not 32767\n            // https://github.com/launchbadge/sqlx/issues/3464\n            // https://www.postgresql.org/docs/current/limits.html\n            let num_params = u16::try_from(arguments.len()).map_err(|_| {\n                err_protocol!(\n                    \"PgConnection::run(): too many arguments for query: {}\",\n                    arguments.len()\n                )\n            })?;\n\n            // prepare the statement if this our first time executing it\n            // always return the statement ID here\n            let (statement, metadata_) = self\n                .get_or_prepare(sql, &arguments.types, persistent, metadata_opt, false)\n                .await?;\n\n            metadata = metadata_;\n\n            // patch holes created during encoding\n            arguments.apply_patches(self, &metadata.parameters).await?;\n\n            // consume messages till `ReadyForQuery` before bind and execute\n            self.wait_until_ready().await?;\n\n            // bind to attach the arguments to the statement and create a portal\n            self.inner.stream.write_msg(Bind {\n                portal: PortalId::UNNAMED,\n                statement,\n                formats: &[PgValueFormat::Binary],\n                num_params,\n                params: &arguments.buffer,\n                result_formats: &[PgValueFormat::Binary],\n            })?;\n\n            // executes the portal up to the passed limit\n            // the protocol-level limit acts nearly identically to the `LIMIT` in SQL\n            self.inner.stream.write_msg(message::Execute {\n                portal: PortalId::UNNAMED,\n                // Non-zero limits cause query plan pessimization by disabling parallel workers:\n                // https://github.com/launchbadge/sqlx/issues/3673\n                limit: 0,\n            })?;\n            // From https://www.postgresql.org/docs/current/protocol-flow.html:\n            //\n            // \"An unnamed portal is destroyed at the end of the transaction, or as\n            // soon as the next Bind statement specifying the unnamed portal as\n            // destination is issued. (Note that a simple Query message also\n            // destroys the unnamed portal.\"\n\n            // we ask the database server to close the unnamed portal and free the associated resources\n            // earlier - after the execution of the current query.\n            self.inner\n                .stream\n                .write_msg(Close::Portal(PortalId::UNNAMED))?;\n\n            // finally, [Sync] asks postgres to process the messages that we sent and respond with\n            // a [ReadyForQuery] message when it's completely done. Theoretically, we could send\n            // dozens of queries before a [Sync] and postgres can handle that. Execution on the server\n            // is still serial but it would reduce round-trips. Some kind of builder pattern that is\n            // termed batching might suit this.\n            self.write_sync();\n\n            // prepared statements are binary\n            PgValueFormat::Binary\n        } else {\n            // Query will trigger a ReadyForQuery\n            self.inner.stream.write_msg(Query(sql))?;\n            self.inner.pending_ready_for_query_count += 1;\n\n            // metadata starts out as \"nothing\"\n            metadata = Arc::new(PgStatementMetadata::default());\n\n            // and unprepared statements are text\n            PgValueFormat::Text\n        };\n\n        self.inner.stream.flush().await?;\n\n        Ok(try_stream! {\n            loop {\n                let message = self.inner.stream.recv().await?;\n\n                match message.format {\n                    BackendMessageFormat::BindComplete\n                    | BackendMessageFormat::ParseComplete\n                    | BackendMessageFormat::ParameterDescription\n                    | BackendMessageFormat::NoData\n                    // unnamed portal has been closed\n                    | BackendMessageFormat::CloseComplete\n                    => {\n                        // harmless messages to ignore\n                    }\n\n                    // \"Execute phase is always terminated by the appearance of\n                    // exactly one of these messages: CommandComplete,\n                    // EmptyQueryResponse (if the portal was created from an\n                    // empty query string), ErrorResponse, or PortalSuspended\"\n                    BackendMessageFormat::CommandComplete => {\n                        // a SQL command completed normally\n                        let cc: CommandComplete = message.decode()?;\n\n                        let rows_affected = cc.rows_affected();\n                        logger.increase_rows_affected(rows_affected);\n                        r#yield!(Either::Left(PgQueryResult {\n                            rows_affected,\n                        }));\n                    }\n\n                    BackendMessageFormat::EmptyQueryResponse => {\n                        // empty query string passed to an unprepared execute\n                    }\n\n                    // Message::ErrorResponse is handled in self.stream.recv()\n\n                    // incomplete query execution has finished\n                    BackendMessageFormat::PortalSuspended => {}\n\n                    BackendMessageFormat::RowDescription => {\n                        // indicates that a *new* set of rows are about to be returned\n                        let (columns, column_names) = self\n                            .handle_row_description(Some(message.decode()?), false, false)\n                            .await?;\n\n                        metadata = Arc::new(PgStatementMetadata {\n                            column_names: Arc::new(column_names),\n                            columns,\n                            parameters: Vec::default(),\n                        });\n                    }\n\n                    BackendMessageFormat::DataRow => {\n                        logger.increment_rows_returned();\n\n                        // one of the set of rows returned by a SELECT, FETCH, etc query\n                        let data: DataRow = message.decode()?;\n                        let row = PgRow {\n                            data,\n                            format,\n                            metadata: Arc::clone(&metadata),\n                        };\n\n                        r#yield!(Either::Right(row));\n                    }\n\n                    BackendMessageFormat::ReadyForQuery => {\n                        // processing of the query string is complete\n                        self.handle_ready_for_query(message)?;\n                        break;\n                    }\n\n                    _ => {\n                        return Err(err_protocol!(\n                            \"execute: unexpected message: {:?}\",\n                            message.format\n                        ));\n                    }\n                }\n            }\n\n            Ok(())\n        })\n    }\n}\n\nimpl<'c> Executor<'c> for &'c mut PgConnection {\n    type Database = Postgres;\n\n    fn fetch_many<'e, 'q, E>(\n        self,\n        mut query: E,\n    ) -> BoxStream<'e, Result<Either<PgQueryResult, PgRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        // False positive: https://github.com/rust-lang/rust-clippy/issues/12560\n        #[allow(clippy::map_clone)]\n        let metadata = query.statement().map(|s| Arc::clone(&s.metadata));\n        let arguments = query.take_arguments().map_err(Error::Encode);\n        let persistent = query.persistent();\n        let sql = query.sql();\n\n        Box::pin(try_stream! {\n            let arguments = arguments?;\n            let mut s = pin!(self.run(sql, arguments, persistent, metadata).await?);\n\n            while let Some(v) = s.try_next().await? {\n                r#yield!(v);\n            }\n\n            Ok(())\n        })\n    }\n\n    fn fetch_optional<'e, 'q, E>(self, mut query: E) -> BoxFuture<'e, Result<Option<PgRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        // False positive: https://github.com/rust-lang/rust-clippy/issues/12560\n        #[allow(clippy::map_clone)]\n        let metadata = query.statement().map(|s| Arc::clone(&s.metadata));\n        let arguments = query.take_arguments().map_err(Error::Encode);\n        let persistent = query.persistent();\n\n        Box::pin(async move {\n            let sql = query.sql();\n            let arguments = arguments?;\n            let mut s = pin!(self.run(sql, arguments, persistent, metadata).await?);\n\n            // With deferred constraints we need to check all responses as we\n            // could get a OK response (with uncommitted data), only to get an\n            // error response after (when the deferred constraint is actually\n            // checked).\n            let mut ret = None;\n            while let Some(result) = s.try_next().await? {\n                match result {\n                    Either::Right(r) if ret.is_none() => ret = Some(r),\n                    _ => {}\n                }\n            }\n            Ok(ret)\n        })\n    }\n\n    fn prepare_with<'e>(\n        self,\n        sql: SqlStr,\n        parameters: &'e [PgTypeInfo],\n    ) -> BoxFuture<'e, Result<PgStatement, Error>>\n    where\n        'c: 'e,\n    {\n        Box::pin(async move {\n            self.wait_until_ready().await?;\n\n            let (_, metadata) = self\n                .get_or_prepare(sql.as_str(), parameters, true, None, true)\n                .await?;\n\n            Ok(PgStatement { sql, metadata })\n        })\n    }\n\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        sql: SqlStr,\n    ) -> BoxFuture<'e, Result<crate::describe::Describe<Self::Database>, Error>>\n    where\n        'c: 'e,\n    {\n        Box::pin(async move {\n            self.wait_until_ready().await?;\n\n            let (stmt_id, metadata) = self\n                .get_or_prepare(sql.as_str(), &[], true, None, true)\n                .await?;\n\n            let nullable = self.get_nullable_for_columns(stmt_id, &metadata).await?;\n\n            Ok(crate::describe::Describe {\n                columns: metadata.columns.clone(),\n                nullable,\n                parameters: Some(Either::Left(metadata.parameters.clone())),\n            })\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/mod.rs",
    "content": "use std::collections::BTreeMap;\nuse std::fmt::{self, Debug, Formatter};\nuse std::future::Future;\nuse std::sync::Arc;\n\nuse crate::HashMap;\n\nuse crate::common::StatementCache;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::io::StatementId;\nuse crate::message::{\n    BackendMessageFormat, Close, Query, ReadyForQuery, ReceivedMessage, Terminate,\n    TransactionStatus,\n};\nuse crate::statement::PgStatementMetadata;\nuse crate::transaction::Transaction;\nuse crate::types::Oid;\nuse crate::{PgConnectOptions, PgTypeInfo, Postgres};\n\npub(crate) use sqlx_core::connection::*;\nuse sqlx_core::sql_str::SqlSafeStr;\n\npub use self::stream::PgStream;\n\n#[cfg(feature = \"offline\")]\nmod describe;\nmod establish;\nmod executor;\nmod resolve;\nmod sasl;\nmod stream;\nmod tls;\n\n/// A connection to a PostgreSQL database.\n///\n/// See [`PgConnectOptions`] for connection URL reference.\npub struct PgConnection {\n    pub(crate) inner: Box<PgConnectionInner>,\n}\n\npub struct PgConnectionInner {\n    // underlying TCP or UDS stream,\n    // wrapped in a potentially TLS stream,\n    // wrapped in a buffered stream\n    pub(crate) stream: PgStream,\n\n    // process id of this backend\n    // used to send cancel requests\n    #[allow(dead_code)]\n    process_id: u32,\n\n    // secret key of this backend\n    // used to send cancel requests\n    #[allow(dead_code)]\n    secret_key: u32,\n\n    // sequence of statement IDs for use in preparing statements\n    // in PostgreSQL, the statement is prepared to a user-supplied identifier\n    next_statement_id: StatementId,\n\n    // cache statement by query string to the id and columns\n    cache_statement: StatementCache<(StatementId, Arc<PgStatementMetadata>)>,\n\n    // cache user-defined types by id <-> info\n    cache_type_info: HashMap<Oid, PgTypeInfo>,\n    cache_type_oid: HashMap<UStr, Oid>,\n    cache_elem_type_to_array: HashMap<Oid, Oid>,\n    cache_table_to_column_names: HashMap<Oid, TableColumns>,\n\n    // number of ReadyForQuery messages that we are currently expecting\n    pub(crate) pending_ready_for_query_count: usize,\n\n    // current transaction status\n    transaction_status: TransactionStatus,\n    pub(crate) transaction_depth: usize,\n\n    log_settings: LogSettings,\n}\n\npub(crate) struct TableColumns {\n    table_name: Arc<str>,\n    /// Attribute number -> name.\n    columns: BTreeMap<i16, Arc<str>>,\n}\n\nimpl PgConnection {\n    /// the version number of the server in `libpq` format\n    pub fn server_version_num(&self) -> Option<u32> {\n        self.inner.stream.server_version_num\n    }\n\n    // will return when the connection is ready for another query\n    pub(crate) async fn wait_until_ready(&mut self) -> Result<(), Error> {\n        if !self.inner.stream.write_buffer_mut().is_empty() {\n            self.inner.stream.flush().await?;\n        }\n\n        while self.inner.pending_ready_for_query_count > 0 {\n            let message = self.inner.stream.recv().await?;\n\n            if let BackendMessageFormat::ReadyForQuery = message.format {\n                self.handle_ready_for_query(message)?;\n            }\n        }\n\n        Ok(())\n    }\n\n    async fn recv_ready_for_query(&mut self) -> Result<(), Error> {\n        let r: ReadyForQuery = self.inner.stream.recv_expect().await?;\n\n        self.inner.pending_ready_for_query_count -= 1;\n        self.inner.transaction_status = r.transaction_status;\n\n        Ok(())\n    }\n\n    #[inline(always)]\n    fn handle_ready_for_query(&mut self, message: ReceivedMessage) -> Result<(), Error> {\n        self.inner.pending_ready_for_query_count = self\n            .inner\n            .pending_ready_for_query_count\n            .checked_sub(1)\n            .ok_or_else(|| err_protocol!(\"received more ReadyForQuery messages than expected\"))?;\n\n        self.inner.transaction_status = message.decode::<ReadyForQuery>()?.transaction_status;\n\n        Ok(())\n    }\n\n    /// Queue a simple query (not prepared) to execute the next time this connection is used.\n    ///\n    /// Used for rolling back transactions and releasing advisory locks.\n    #[inline(always)]\n    pub(crate) fn queue_simple_query(&mut self, query: &str) -> Result<(), Error> {\n        self.inner.stream.write_msg(Query(query))?;\n        self.inner.pending_ready_for_query_count += 1;\n\n        Ok(())\n    }\n\n    pub(crate) fn in_transaction(&self) -> bool {\n        match self.inner.transaction_status {\n            TransactionStatus::Transaction => true,\n            TransactionStatus::Error | TransactionStatus::Idle => false,\n        }\n    }\n}\n\nimpl Debug for PgConnection {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"PgConnection\").finish()\n    }\n}\n\nimpl Connection for PgConnection {\n    type Database = Postgres;\n\n    type Options = PgConnectOptions;\n\n    async fn close(mut self) -> Result<(), Error> {\n        // The normal, graceful termination procedure is that the frontend sends a Terminate\n        // message and immediately closes the connection.\n\n        // On receipt of this message, the backend closes the\n        // connection and terminates.\n        self.inner.stream.send(Terminate).await?;\n        self.inner.stream.shutdown().await?;\n\n        Ok(())\n    }\n\n    async fn close_hard(mut self) -> Result<(), Error> {\n        self.inner.stream.shutdown().await?;\n\n        Ok(())\n    }\n\n    async fn ping(&mut self) -> Result<(), Error> {\n        // Users were complaining about this showing up in query statistics on the server.\n        // By sending a comment we avoid an error if the connection was in the middle of a rowset\n        // self.execute(\"/* SQLx ping */\").map_ok(|_| ()).boxed()\n\n        // The simplest call-and-response that's possible.\n        self.write_sync();\n        self.wait_until_ready().await\n    }\n\n    fn begin(\n        &mut self,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_ {\n        Transaction::begin(self, None)\n    }\n\n    fn begin_with(\n        &mut self,\n        statement: impl SqlSafeStr,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        Transaction::begin(self, Some(statement.into_sql_str()))\n    }\n\n    fn cached_statements_size(&self) -> usize {\n        self.inner.cache_statement.len()\n    }\n\n    async fn clear_cached_statements(&mut self) -> Result<(), Error> {\n        self.inner.cache_type_oid.clear();\n\n        let mut cleared = 0_usize;\n\n        self.wait_until_ready().await?;\n\n        while let Some((id, _)) = self.inner.cache_statement.remove_lru() {\n            self.inner.stream.write_msg(Close::Statement(id))?;\n            cleared += 1;\n        }\n\n        if cleared > 0 {\n            self.write_sync();\n            self.inner.stream.flush().await?;\n\n            self.wait_for_close_complete(cleared).await?;\n            self.recv_ready_for_query().await?;\n        }\n\n        Ok(())\n    }\n\n    fn shrink_buffers(&mut self) {\n        self.inner.stream.shrink_buffers();\n    }\n\n    #[doc(hidden)]\n    fn flush(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        self.wait_until_ready()\n    }\n\n    #[doc(hidden)]\n    fn should_flush(&self) -> bool {\n        !self.inner.stream.write_buffer().is_empty()\n    }\n}\n\n// Implement `AsMut<Self>` so that `PgConnection` can be wrapped in\n// a `PgAdvisoryLockGuard`.\n//\n// See: https://github.com/launchbadge/sqlx/issues/2520\nimpl AsMut<PgConnection> for PgConnection {\n    fn as_mut(&mut self) -> &mut PgConnection {\n        self\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/resolve.rs",
    "content": "use crate::connection::TableColumns;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::message::{ParameterDescription, RowDescription};\nuse crate::query_as::query_as;\nuse crate::query_scalar::query_scalar;\nuse crate::type_info::{PgArrayOf, PgCustomType, PgType, PgTypeKind};\nuse crate::types::Oid;\nuse crate::HashMap;\nuse crate::{PgColumn, PgConnection, PgTypeInfo};\nuse sqlx_core::column::{ColumnOrigin, TableColumn};\nuse std::sync::Arc;\n\n/// Describes the type of the `pg_type.typtype` column\n///\n/// See <https://www.postgresql.org/docs/13/catalog-pg-type.html>\n#[derive(Copy, Clone, Debug, Eq, PartialEq)]\nenum TypType {\n    Base,\n    Composite,\n    Domain,\n    Enum,\n    Pseudo,\n    Range,\n}\n\nimpl TryFrom<i8> for TypType {\n    type Error = ();\n\n    fn try_from(t: i8) -> Result<Self, Self::Error> {\n        let t = u8::try_from(t).or(Err(()))?;\n\n        let t = match t {\n            b'b' => Self::Base,\n            b'c' => Self::Composite,\n            b'd' => Self::Domain,\n            b'e' => Self::Enum,\n            b'p' => Self::Pseudo,\n            b'r' => Self::Range,\n            _ => return Err(()),\n        };\n        Ok(t)\n    }\n}\n\n/// Describes the type of the `pg_type.typcategory` column\n///\n/// See <https://www.postgresql.org/docs/13/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE>\n#[derive(Copy, Clone, Debug, Eq, PartialEq)]\nenum TypCategory {\n    Array,\n    Boolean,\n    Composite,\n    DateTime,\n    Enum,\n    Geometric,\n    Network,\n    Numeric,\n    Pseudo,\n    Range,\n    String,\n    Timespan,\n    User,\n    BitString,\n    Unknown,\n}\n\nimpl TryFrom<i8> for TypCategory {\n    type Error = ();\n\n    fn try_from(c: i8) -> Result<Self, Self::Error> {\n        let c = u8::try_from(c).or(Err(()))?;\n\n        let c = match c {\n            b'A' => Self::Array,\n            b'B' => Self::Boolean,\n            b'C' => Self::Composite,\n            b'D' => Self::DateTime,\n            b'E' => Self::Enum,\n            b'G' => Self::Geometric,\n            b'I' => Self::Network,\n            b'N' => Self::Numeric,\n            b'P' => Self::Pseudo,\n            b'R' => Self::Range,\n            b'S' => Self::String,\n            b'T' => Self::Timespan,\n            b'U' => Self::User,\n            b'V' => Self::BitString,\n            b'X' => Self::Unknown,\n            _ => return Err(()),\n        };\n        Ok(c)\n    }\n}\n\nimpl PgConnection {\n    pub(super) async fn handle_row_description(\n        &mut self,\n        desc: Option<RowDescription>,\n        fetch_type_info: bool,\n        fetch_column_description: bool,\n    ) -> Result<(Vec<PgColumn>, HashMap<UStr, usize>), Error> {\n        let mut columns = Vec::new();\n        let mut column_names = HashMap::new();\n\n        let desc = if let Some(desc) = desc {\n            desc\n        } else {\n            // no rows\n            return Ok((columns, column_names));\n        };\n\n        columns.reserve(desc.fields.len());\n        column_names.reserve(desc.fields.len());\n\n        for (index, field) in desc.fields.into_iter().enumerate() {\n            let name = UStr::from(field.name);\n\n            let type_info = self\n                .maybe_fetch_type_info_by_oid(field.data_type_id, fetch_type_info)\n                .await?;\n\n            let origin = if let (Some(relation_oid), Some(attribute_no)) =\n                (field.relation_id, field.relation_attribute_no)\n            {\n                self.maybe_fetch_column_origin(relation_oid, attribute_no, fetch_column_description)\n                    .await?\n            } else {\n                ColumnOrigin::Expression\n            };\n\n            let column = PgColumn {\n                ordinal: index,\n                name: name.clone(),\n                type_info,\n                relation_id: field.relation_id,\n                relation_attribute_no: field.relation_attribute_no,\n                origin,\n            };\n\n            columns.push(column);\n            column_names.insert(name, index);\n        }\n\n        Ok((columns, column_names))\n    }\n\n    pub(super) async fn handle_parameter_description(\n        &mut self,\n        desc: ParameterDescription,\n    ) -> Result<Vec<PgTypeInfo>, Error> {\n        let mut params = Vec::with_capacity(desc.types.len());\n\n        for ty in desc.types {\n            params.push(self.maybe_fetch_type_info_by_oid(ty, true).await?);\n        }\n\n        Ok(params)\n    }\n\n    async fn maybe_fetch_type_info_by_oid(\n        &mut self,\n        oid: Oid,\n        should_fetch: bool,\n    ) -> Result<PgTypeInfo, Error> {\n        // first we check if this is a built-in type\n        // in the average application, the vast majority of checks should flow through this\n        if let Some(info) = PgTypeInfo::try_from_oid(oid) {\n            return Ok(info);\n        }\n\n        // next we check a local cache for user-defined type names <-> object id\n        if let Some(info) = self.inner.cache_type_info.get(&oid) {\n            return Ok(info.clone());\n        }\n\n        // fallback to asking the database directly for a type name\n        if should_fetch {\n            // we're boxing this future here so we can use async recursion\n            let info = Box::pin(async { self.fetch_type_by_oid(oid).await }).await?;\n\n            // cache the type name <-> oid relationship in a paired hashmap\n            // so we don't come down this road again\n            self.inner.cache_type_info.insert(oid, info.clone());\n            self.inner\n                .cache_type_oid\n                .insert(info.0.name().to_string().into(), oid);\n\n            Ok(info)\n        } else {\n            // we are not in a place that *can* run a query\n            // this generally means we are in the middle of another query\n            // this _should_ only happen for complex types sent through the TEXT protocol\n            // we're open to ideas to correct this.. but it'd probably be more efficient to figure\n            // out a way to \"prime\" the type cache for connections rather than make this\n            // fallback work correctly for complex user-defined types for the TEXT protocol\n            Ok(PgTypeInfo(PgType::DeclareWithOid(oid)))\n        }\n    }\n\n    async fn maybe_fetch_column_origin(\n        &mut self,\n        relation_id: Oid,\n        attribute_no: i16,\n        should_fetch: bool,\n    ) -> Result<ColumnOrigin, Error> {\n        if let Some(origin) = self\n            .inner\n            .cache_table_to_column_names\n            .get(&relation_id)\n            .and_then(|table_columns| {\n                let column_name = table_columns.columns.get(&attribute_no).cloned()?;\n\n                Some(ColumnOrigin::Table(TableColumn {\n                    table: table_columns.table_name.clone(),\n                    name: column_name,\n                }))\n            })\n        {\n            return Ok(origin);\n        }\n\n        if !should_fetch {\n            return Ok(ColumnOrigin::Unknown);\n        }\n\n        // Looking up the table name _may_ end up being redundant,\n        // but the round-trip to the server is by far the most expensive part anyway.\n        let Some((table_name, column_name)): Option<(String, String)> = query_as(\n            // language=PostgreSQL\n            \"SELECT $1::oid::regclass::text, attname \\\n                 FROM pg_catalog.pg_attribute \\\n                 WHERE attrelid = $1 AND attnum = $2\",\n        )\n        .bind(relation_id)\n        .bind(attribute_no)\n        .fetch_optional(&mut *self)\n        .await?\n        else {\n            // The column/table doesn't exist anymore for whatever reason.\n            return Ok(ColumnOrigin::Unknown);\n        };\n\n        let table_columns = self\n            .inner\n            .cache_table_to_column_names\n            .entry(relation_id)\n            .or_insert_with(|| TableColumns {\n                table_name: table_name.into(),\n                columns: Default::default(),\n            });\n\n        let column_name = table_columns\n            .columns\n            .entry(attribute_no)\n            .or_insert(column_name.into());\n\n        Ok(ColumnOrigin::Table(TableColumn {\n            table: table_columns.table_name.clone(),\n            name: Arc::clone(column_name),\n        }))\n    }\n\n    async fn fetch_type_by_oid(&mut self, oid: Oid) -> Result<PgTypeInfo, Error> {\n        let (name, typ_type, category, relation_id, element, base_type): (\n            String,\n            i8,\n            i8,\n            Oid,\n            Oid,\n            Oid,\n        ) = query_as(\n            // Converting the OID to `regtype` and then `text` will give us the name that\n            // the type will need to be found at by search_path.\n            \"SELECT oid::regtype::text, \\\n                     typtype, \\\n                     typcategory, \\\n                     typrelid, \\\n                     typelem, \\\n                     typbasetype \\\n                     FROM pg_catalog.pg_type \\\n                     WHERE oid = $1\",\n        )\n        .bind(oid)\n        .fetch_one(&mut *self)\n        .await?;\n\n        let typ_type = TypType::try_from(typ_type);\n        let category = TypCategory::try_from(category);\n\n        match (typ_type, category) {\n            (Ok(TypType::Domain), _) => self.fetch_domain_by_oid(oid, base_type, name).await,\n\n            (Ok(TypType::Base), Ok(TypCategory::Array)) => {\n                Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n                    kind: PgTypeKind::Array(\n                        self.maybe_fetch_type_info_by_oid(element, true).await?,\n                    ),\n                    name: name.into(),\n                    oid,\n                }))))\n            }\n\n            (Ok(TypType::Pseudo), Ok(TypCategory::Pseudo)) => {\n                Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n                    kind: PgTypeKind::Pseudo,\n                    name: name.into(),\n                    oid,\n                }))))\n            }\n\n            (Ok(TypType::Range), Ok(TypCategory::Range)) => {\n                self.fetch_range_by_oid(oid, name).await\n            }\n\n            (Ok(TypType::Enum), Ok(TypCategory::Enum)) => self.fetch_enum_by_oid(oid, name).await,\n\n            (Ok(TypType::Composite), Ok(TypCategory::Composite)) => {\n                self.fetch_composite_by_oid(oid, relation_id, name).await\n            }\n\n            _ => Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n                kind: PgTypeKind::Simple,\n                name: name.into(),\n                oid,\n            })))),\n        }\n    }\n\n    async fn fetch_enum_by_oid(&mut self, oid: Oid, name: String) -> Result<PgTypeInfo, Error> {\n        let variants: Vec<String> = query_scalar(\n            r#\"\nSELECT enumlabel\nFROM pg_catalog.pg_enum\nWHERE enumtypid = $1\nORDER BY enumsortorder\n            \"#,\n        )\n        .bind(oid)\n        .fetch_all(self)\n        .await?;\n\n        Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n            oid,\n            name: name.into(),\n            kind: PgTypeKind::Enum(Arc::from(variants)),\n        }))))\n    }\n\n    async fn fetch_composite_by_oid(\n        &mut self,\n        oid: Oid,\n        relation_id: Oid,\n        name: String,\n    ) -> Result<PgTypeInfo, Error> {\n        let raw_fields: Vec<(String, Oid)> = query_as(\n            r#\"\nSELECT attname, atttypid\nFROM pg_catalog.pg_attribute\nWHERE attrelid = $1\nAND NOT attisdropped\nAND attnum > 0\nORDER BY attnum\n                \"#,\n        )\n        .bind(relation_id)\n        .fetch_all(&mut *self)\n        .await?;\n\n        let mut fields = Vec::new();\n\n        for (field_name, field_oid) in raw_fields.into_iter() {\n            let field_type = self.maybe_fetch_type_info_by_oid(field_oid, true).await?;\n\n            fields.push((field_name, field_type));\n        }\n\n        Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n            oid,\n            name: name.into(),\n            kind: PgTypeKind::Composite(Arc::from(fields)),\n        }))))\n    }\n\n    async fn fetch_domain_by_oid(\n        &mut self,\n        oid: Oid,\n        base_type: Oid,\n        name: String,\n    ) -> Result<PgTypeInfo, Error> {\n        let base_type = self.maybe_fetch_type_info_by_oid(base_type, true).await?;\n\n        Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n            oid,\n            name: name.into(),\n            kind: PgTypeKind::Domain(base_type),\n        }))))\n    }\n\n    async fn fetch_range_by_oid(&mut self, oid: Oid, name: String) -> Result<PgTypeInfo, Error> {\n        let element_oid: Oid = query_scalar(\n            r#\"\nSELECT rngsubtype\nFROM pg_catalog.pg_range\nWHERE rngtypid = $1\n                \"#,\n        )\n        .bind(oid)\n        .fetch_one(&mut *self)\n        .await?;\n\n        let element = self.maybe_fetch_type_info_by_oid(element_oid, true).await?;\n\n        Ok(PgTypeInfo(PgType::Custom(Arc::new(PgCustomType {\n            kind: PgTypeKind::Range(element),\n            name: name.into(),\n            oid,\n        }))))\n    }\n\n    pub(crate) async fn resolve_type_id(&mut self, ty: &PgType) -> Result<Oid, Error> {\n        if let Some(oid) = ty.try_oid() {\n            return Ok(oid);\n        }\n\n        match ty {\n            PgType::DeclareWithName(name) => self.fetch_type_id_by_name(name).await,\n            PgType::DeclareArrayOf(array) => self.fetch_array_type_id(array).await,\n            // `.try_oid()` should return `Some()` or it should be covered here\n            _ => unreachable!(\"(bug) OID should be resolvable for type {ty:?}\"),\n        }\n    }\n\n    pub(crate) async fn fetch_type_id_by_name(&mut self, name: &str) -> Result<Oid, Error> {\n        if let Some(oid) = self.inner.cache_type_oid.get(name) {\n            return Ok(*oid);\n        }\n\n        // language=SQL\n        let (oid,): (Oid,) = query_as(\"SELECT $1::regtype::oid\")\n            .bind(name)\n            .fetch_optional(&mut *self)\n            .await?\n            .ok_or_else(|| Error::TypeNotFound {\n                type_name: name.into(),\n            })?;\n\n        self.inner\n            .cache_type_oid\n            .insert(name.to_string().into(), oid);\n        Ok(oid)\n    }\n\n    pub(crate) async fn fetch_array_type_id(&mut self, array: &PgArrayOf) -> Result<Oid, Error> {\n        if let Some(oid) = self\n            .inner\n            .cache_type_oid\n            .get(&array.elem_name)\n            .and_then(|elem_oid| self.inner.cache_elem_type_to_array.get(elem_oid))\n        {\n            return Ok(*oid);\n        }\n\n        // language=SQL\n        let (elem_oid, array_oid): (Oid, Oid) =\n            query_as(\"SELECT oid, typarray FROM pg_catalog.pg_type WHERE oid = $1::regtype::oid\")\n                .bind(&*array.elem_name)\n                .fetch_optional(&mut *self)\n                .await?\n                .ok_or_else(|| Error::TypeNotFound {\n                    type_name: array.name.to_string(),\n                })?;\n\n        // Avoids copying `elem_name` until necessary\n        self.inner\n            .cache_type_oid\n            .entry_ref(&array.elem_name)\n            .insert(elem_oid);\n        self.inner\n            .cache_elem_type_to_array\n            .insert(elem_oid, array_oid);\n\n        Ok(array_oid)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/sasl.rs",
    "content": "use crate::connection::stream::PgStream;\nuse crate::error::Error;\nuse crate::message::{Authentication, AuthenticationSasl, SaslInitialResponse, SaslResponse};\nuse crate::rt;\nuse crate::PgConnectOptions;\nuse hmac::{Hmac, Mac};\nuse rand::Rng;\nuse sha2::{Digest, Sha256};\nuse stringprep::saslprep;\n\nuse base64::prelude::{Engine as _, BASE64_STANDARD};\n\nconst GS2_HEADER: &str = \"n,,\";\nconst CHANNEL_ATTR: &str = \"c\";\nconst USERNAME_ATTR: &str = \"n\";\nconst CLIENT_PROOF_ATTR: &str = \"p\";\nconst NONCE_ATTR: &str = \"r\";\n\npub(crate) async fn authenticate(\n    stream: &mut PgStream,\n    options: &PgConnectOptions,\n    data: AuthenticationSasl,\n) -> Result<(), Error> {\n    let mut has_sasl = false;\n    let mut has_sasl_plus = false;\n    let mut unknown = Vec::new();\n\n    for mechanism in data.mechanisms() {\n        match mechanism {\n            \"SCRAM-SHA-256\" => {\n                has_sasl = true;\n            }\n\n            \"SCRAM-SHA-256-PLUS\" => {\n                has_sasl_plus = true;\n            }\n\n            _ => {\n                unknown.push(mechanism.to_owned());\n            }\n        }\n    }\n\n    if !has_sasl_plus && !has_sasl {\n        return Err(err_protocol!(\n            \"unsupported SASL authentication mechanisms: {}\",\n            unknown.join(\", \")\n        ));\n    }\n\n    // channel-binding = \"c=\" base64\n    let mut channel_binding = format!(\"{CHANNEL_ATTR}=\");\n    BASE64_STANDARD.encode_string(GS2_HEADER, &mut channel_binding);\n\n    // \"n=\" saslname ;; Usernames are prepared using SASLprep.\n    let username = format!(\"{}={}\", USERNAME_ATTR, options.username);\n    let username = match saslprep(&username) {\n        Ok(v) => v,\n        // TODO(danielakhterov): Remove panic when we have proper support for configuration errors\n        Err(_) => panic!(\"Failed to saslprep username\"),\n    };\n\n    // nonce = \"r=\" c-nonce [s-nonce] ;; Second part provided by server.\n    let nonce = gen_nonce();\n\n    // client-first-message-bare = [reserved-mext \",\"] username \",\" nonce [\",\" extensions]\n    let client_first_message_bare = format!(\"{username},{nonce}\");\n\n    let client_first_message = format!(\"{GS2_HEADER}{client_first_message_bare}\");\n\n    stream\n        .send(SaslInitialResponse {\n            response: &client_first_message,\n            plus: false,\n        })\n        .await?;\n\n    let cont = match stream.recv_expect().await? {\n        Authentication::SaslContinue(data) => data,\n\n        auth => {\n            return Err(err_protocol!(\n                \"expected SASLContinue but received {:?}\",\n                auth\n            ));\n        }\n    };\n\n    // SaltedPassword := Hi(Normalize(password), salt, i)\n    let salted_password = hi(\n        options.password.as_deref().unwrap_or_default(),\n        &cont.salt,\n        cont.iterations,\n    )\n    .await?;\n\n    // ClientKey := HMAC(SaltedPassword, \"Client Key\")\n    let mut mac = Hmac::<Sha256>::new_from_slice(&salted_password).map_err(Error::protocol)?;\n    mac.update(b\"Client Key\");\n\n    let client_key = mac.finalize().into_bytes();\n\n    // StoredKey := H(ClientKey)\n    let stored_key = Sha256::digest(client_key);\n\n    // client-final-message-without-proof\n    let client_final_message_wo_proof = format!(\n        \"{channel_binding},r={nonce}\",\n        channel_binding = channel_binding,\n        nonce = &cont.nonce\n    );\n\n    // AuthMessage := client-first-message-bare + \",\" + server-first-message + \",\" + client-final-message-without-proof\n    let auth_message = format!(\n        \"{client_first_message_bare},{server_first_message},{client_final_message_wo_proof}\",\n        client_first_message_bare = client_first_message_bare,\n        server_first_message = cont.message,\n        client_final_message_wo_proof = client_final_message_wo_proof\n    );\n\n    // ClientSignature := HMAC(StoredKey, AuthMessage)\n    let mut mac = Hmac::<Sha256>::new_from_slice(&stored_key).map_err(Error::protocol)?;\n    mac.update(auth_message.as_bytes());\n\n    let client_signature = mac.finalize().into_bytes();\n\n    // ClientProof := ClientKey XOR ClientSignature\n    let client_proof: Vec<u8> = client_key\n        .iter()\n        .zip(client_signature.iter())\n        .map(|(&a, &b)| a ^ b)\n        .collect();\n\n    // ServerKey := HMAC(SaltedPassword, \"Server Key\")\n    let mut mac = Hmac::<Sha256>::new_from_slice(&salted_password).map_err(Error::protocol)?;\n    mac.update(b\"Server Key\");\n\n    let server_key = mac.finalize().into_bytes();\n\n    // ServerSignature := HMAC(ServerKey, AuthMessage)\n    let mut mac = Hmac::<Sha256>::new_from_slice(&server_key).map_err(Error::protocol)?;\n    mac.update(auth_message.as_bytes());\n\n    // client-final-message = client-final-message-without-proof \",\" proof\n    let mut client_final_message = format!(\"{client_final_message_wo_proof},{CLIENT_PROOF_ATTR}=\");\n    BASE64_STANDARD.encode_string(client_proof, &mut client_final_message);\n\n    stream.send(SaslResponse(&client_final_message)).await?;\n\n    let data = match stream.recv_expect().await? {\n        Authentication::SaslFinal(data) => data,\n\n        auth => {\n            return Err(err_protocol!(\"expected SASLFinal but received {:?}\", auth));\n        }\n    };\n\n    // authentication is only considered valid if this verification passes\n    mac.verify_slice(&data.verifier).map_err(Error::protocol)?;\n\n    Ok(())\n}\n\n// nonce is a sequence of random printable bytes\nfn gen_nonce() -> String {\n    let mut rng = rand::thread_rng();\n    let count = rng.gen_range(64..128);\n\n    // printable = %x21-2B / %x2D-7E\n    // ;; Printable ASCII except \",\".\n    // ;; Note that any \"printable\" is also\n    // ;; a valid \"value\".\n    let nonce: String = std::iter::repeat(())\n        .map(|()| {\n            let mut c = rng.gen_range(0x21u8..0x7F);\n\n            while c == 0x2C {\n                c = rng.gen_range(0x21u8..0x7F);\n            }\n\n            c\n        })\n        .take(count)\n        .map(|c| c as char)\n        .collect();\n\n    rng.gen_range(32..128);\n    format!(\"{NONCE_ATTR}={nonce}\")\n}\n\n// Hi(str, salt, i):\nasync fn hi<'a>(s: &'a str, salt: &'a [u8], iter_count: u32) -> Result<[u8; 32], Error> {\n    let mut mac = Hmac::<Sha256>::new_from_slice(s.as_bytes()).map_err(Error::protocol)?;\n\n    mac.update(salt);\n    mac.update(&1u32.to_be_bytes());\n\n    let mut u = mac.finalize_reset().into_bytes();\n    let mut hi = u;\n\n    for i in 1..iter_count {\n        mac.update(u.as_slice());\n        u = mac.finalize_reset().into_bytes();\n        hi = hi.iter().zip(u.iter()).map(|(&a, &b)| a ^ b).collect();\n\n        // For large iteration counts, this process can take a long time and block the event loop.\n        // It was measured as taking ~50ms for 4096 iterations (the default) on a developer machine.\n        // If we want to yield every 10-100us (as generally advised for tokio), then we can yield\n        // every 5 iterations which should be every ~50us.\n        if i % 5 == 0 {\n            rt::yield_now().await;\n        }\n    }\n\n    Ok(hi.into())\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/stream.rs",
    "content": "use std::collections::BTreeMap;\nuse std::ops::{ControlFlow, Deref, DerefMut};\nuse std::str::FromStr;\n\nuse futures_channel::mpsc::UnboundedSender;\nuse futures_util::SinkExt;\nuse log::Level;\nuse sqlx_core::bytes::Buf;\n\nuse crate::connection::tls::MaybeUpgradeTls;\nuse crate::error::Error;\nuse crate::message::{\n    BackendMessage, BackendMessageFormat, EncodeMessage, FrontendMessage, Notice, Notification,\n    ParameterStatus, ReceivedMessage,\n};\nuse crate::net::{self, BufferedSocket, Socket};\nuse crate::{PgConnectOptions, PgDatabaseError, PgSeverity};\n\n// the stream is a separate type from the connection to uphold the invariant where an instantiated\n// [PgConnection] is a **valid** connection to postgres\n\n// when a new connection is asked for, we work directly on the [PgStream] type until the\n// connection is fully established\n\n// in other words, `self` in any PgConnection method is a live connection to postgres that\n// is fully prepared to receive queries\n\npub struct PgStream {\n    // A trait object is okay here as the buffering amortizes the overhead of both the dynamic\n    // function call as well as the syscall.\n    inner: BufferedSocket<Box<dyn Socket>>,\n\n    // buffer of unreceived notification messages from `PUBLISH`\n    // this is set when creating a PgListener and only written to if that listener is\n    // re-used for query execution in-between receiving messages\n    pub(crate) notifications: Option<UnboundedSender<Notification>>,\n\n    pub(crate) parameter_statuses: BTreeMap<String, String>,\n\n    pub(crate) server_version_num: Option<u32>,\n}\n\nimpl PgStream {\n    pub(super) async fn connect(options: &PgConnectOptions) -> Result<Self, Error> {\n        let socket_result = match options.fetch_socket() {\n            Some(ref path) => net::connect_uds(path, MaybeUpgradeTls(options)).await?,\n            None => net::connect_tcp(&options.host, options.port, MaybeUpgradeTls(options)).await?,\n        };\n\n        let socket = socket_result?;\n\n        Ok(Self {\n            inner: BufferedSocket::new(socket),\n            notifications: None,\n            parameter_statuses: BTreeMap::default(),\n            server_version_num: None,\n        })\n    }\n\n    #[inline(always)]\n    pub(crate) fn write_msg(&mut self, message: impl FrontendMessage) -> Result<(), Error> {\n        self.write(EncodeMessage(message))\n    }\n\n    pub(crate) async fn send<T>(&mut self, message: T) -> Result<(), Error>\n    where\n        T: FrontendMessage,\n    {\n        self.write_msg(message)?;\n        self.flush().await?;\n        Ok(())\n    }\n\n    // Expect a specific type and format\n    pub(crate) async fn recv_expect<B: BackendMessage>(&mut self) -> Result<B, Error> {\n        self.recv().await?.decode()\n    }\n\n    pub(crate) async fn recv_unchecked(&mut self) -> Result<ReceivedMessage, Error> {\n        // NOTE: to not break everything, this should be cancel-safe;\n        // DO NOT modify `buf` unless a full message has been read\n        self.inner\n            .try_read(|buf| {\n                // all packets in postgres start with a 5-byte header\n                // this header contains the message type and the total length of the message\n                let Some(mut header) = buf.get(..5) else {\n                    return Ok(ControlFlow::Continue(5));\n                };\n\n                let format = BackendMessageFormat::try_from_u8(header.get_u8())?;\n\n                let message_len = header.get_u32() as usize;\n\n                let expected_len = message_len\n                    .checked_add(1)\n                    // this shouldn't really happen but is mostly a sanity check\n                    .ok_or_else(|| {\n                        err_protocol!(\"message_len + 1 overflows usize: {message_len}\")\n                    })?;\n\n                if buf.len() < expected_len {\n                    return Ok(ControlFlow::Continue(expected_len));\n                }\n\n                // `buf` SHOULD NOT be modified ABOVE this line\n\n                // pop off the format code since it's not counted in `message_len`\n                buf.advance(1);\n\n                // consume the message, including the length prefix\n                let mut contents = buf.split_to(message_len).freeze();\n\n                // cut off the length prefix\n                contents.advance(4);\n\n                Ok(ControlFlow::Break(ReceivedMessage { format, contents }))\n            })\n            .await\n    }\n\n    // Get the next message from the server\n    // May wait for more data from the server\n    pub(crate) async fn recv(&mut self) -> Result<ReceivedMessage, Error> {\n        loop {\n            let message = self.recv_unchecked().await?;\n\n            match message.format {\n                BackendMessageFormat::ErrorResponse => {\n                    // An error returned from the database server.\n                    return Err(message.decode::<PgDatabaseError>()?.into());\n                }\n\n                BackendMessageFormat::NotificationResponse => {\n                    if let Some(buffer) = &mut self.notifications {\n                        let notification: Notification = message.decode()?;\n                        let _ = buffer.send(notification).await;\n\n                        continue;\n                    }\n                }\n\n                BackendMessageFormat::ParameterStatus => {\n                    // informs the frontend about the current (initial)\n                    // setting of backend parameters\n\n                    let ParameterStatus { name, value } = message.decode()?;\n                    // TODO: handle `client_encoding`, `DateStyle` change\n\n                    match name.as_str() {\n                        \"server_version\" => {\n                            self.server_version_num = parse_server_version(&value);\n                        }\n                        _ => {\n                            self.parameter_statuses.insert(name, value);\n                        }\n                    }\n\n                    continue;\n                }\n\n                BackendMessageFormat::NoticeResponse => {\n                    // do we need this to be more configurable?\n                    // if you are reading this comment and think so, open an issue\n\n                    let notice: Notice = message.decode()?;\n\n                    let (log_level, tracing_level) = match notice.severity() {\n                        PgSeverity::Fatal | PgSeverity::Panic | PgSeverity::Error => {\n                            (Level::Error, tracing::Level::ERROR)\n                        }\n                        PgSeverity::Warning => (Level::Warn, tracing::Level::WARN),\n                        PgSeverity::Notice => (Level::Info, tracing::Level::INFO),\n                        PgSeverity::Debug => (Level::Debug, tracing::Level::DEBUG),\n                        PgSeverity::Info | PgSeverity::Log => (Level::Trace, tracing::Level::TRACE),\n                    };\n\n                    let log_is_enabled = log::log_enabled!(\n                        target: \"sqlx::postgres::notice\",\n                        log_level\n                    ) || sqlx_core::private_tracing_dynamic_enabled!(\n                        target: \"sqlx::postgres::notice\",\n                        tracing_level\n                    );\n                    if log_is_enabled {\n                        sqlx_core::private_tracing_dynamic_event!(\n                            target: \"sqlx::postgres::notice\",\n                            tracing_level,\n                            message = notice.message()\n                        );\n                    }\n\n                    continue;\n                }\n\n                _ => {}\n            }\n\n            return Ok(message);\n        }\n    }\n}\n\nimpl Deref for PgStream {\n    type Target = BufferedSocket<Box<dyn Socket>>;\n\n    #[inline]\n    fn deref(&self) -> &Self::Target {\n        &self.inner\n    }\n}\n\nimpl DerefMut for PgStream {\n    #[inline]\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.inner\n    }\n}\n\n// reference:\n// https://github.com/postgres/postgres/blob/6feebcb6b44631c3dc435e971bd80c2dd218a5ab/src/interfaces/libpq/fe-exec.c#L1030-L1065\nfn parse_server_version(s: &str) -> Option<u32> {\n    let mut parts = Vec::<u32>::with_capacity(3);\n\n    let mut from = 0;\n    let mut chs = s.char_indices().peekable();\n    while let Some((i, ch)) = chs.next() {\n        match ch {\n            '.' => {\n                if let Ok(num) = u32::from_str(&s[from..i]) {\n                    parts.push(num);\n                    from = i + 1;\n                } else {\n                    break;\n                }\n            }\n            _ if ch.is_ascii_digit() => {\n                if chs.peek().is_none() {\n                    if let Ok(num) = u32::from_str(&s[from..]) {\n                        parts.push(num);\n                    }\n                    break;\n                }\n            }\n            _ => {\n                if let Ok(num) = u32::from_str(&s[from..i]) {\n                    parts.push(num);\n                }\n                break;\n            }\n        };\n    }\n\n    let version_num = match parts.as_slice() {\n        [major, minor, rev] => (100 * major + minor) * 100 + rev,\n        [major, minor] if *major >= 10 => 100 * 100 * major + minor,\n        [major, minor] => (100 * major + minor) * 100,\n        [major] => 100 * 100 * major,\n        _ => return None,\n    };\n\n    Some(version_num)\n}\n\n#[cfg(test)]\nmod tests {\n    use super::parse_server_version;\n\n    #[test]\n    fn test_parse_server_version_num() {\n        // old style\n        assert_eq!(parse_server_version(\"9.6.1\"), Some(90601));\n        // new style\n        assert_eq!(parse_server_version(\"10.1\"), Some(100001));\n        // old style without minor version\n        assert_eq!(parse_server_version(\"9.6devel\"), Some(90600));\n        // new style without minor version, e.g.  */\n        assert_eq!(parse_server_version(\"10devel\"), Some(100000));\n        assert_eq!(parse_server_version(\"13devel87\"), Some(130000));\n        // unknown\n        assert_eq!(parse_server_version(\"unknown\"), None);\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/connection/tls.rs",
    "content": "use crate::error::Error;\nuse crate::net::tls::{self, TlsConfig};\nuse crate::net::{Socket, SocketIntoBox, WithSocket};\n\nuse crate::message::SslRequest;\nuse crate::{PgConnectOptions, PgSslMode};\n\npub struct MaybeUpgradeTls<'a>(pub &'a PgConnectOptions);\n\nimpl WithSocket for MaybeUpgradeTls<'_> {\n    type Output = crate::Result<Box<dyn Socket>>;\n\n    async fn with_socket<S: Socket>(self, socket: S) -> Self::Output {\n        maybe_upgrade(socket, self.0).await\n    }\n}\n\nasync fn maybe_upgrade<S: Socket>(\n    mut socket: S,\n    options: &PgConnectOptions,\n) -> Result<Box<dyn Socket>, Error> {\n    // https://www.postgresql.org/docs/12/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS\n    match options.ssl_mode {\n        // FIXME: Implement ALLOW\n        PgSslMode::Allow | PgSslMode::Disable => return Ok(Box::new(socket)),\n\n        PgSslMode::Prefer => {\n            if !tls::available() {\n                return Ok(Box::new(socket));\n            }\n\n            // try upgrade, but its okay if we fail\n            if !request_upgrade(&mut socket, options).await? {\n                return Ok(Box::new(socket));\n            }\n        }\n\n        PgSslMode::Require | PgSslMode::VerifyFull | PgSslMode::VerifyCa => {\n            tls::error_if_unavailable()?;\n\n            if !request_upgrade(&mut socket, options).await? {\n                // upgrade failed, die\n                return Err(Error::Tls(\"server does not support TLS\".into()));\n            }\n        }\n    }\n\n    let accept_invalid_certs = !matches!(\n        options.ssl_mode,\n        PgSslMode::VerifyCa | PgSslMode::VerifyFull\n    );\n    let accept_invalid_hostnames = !matches!(options.ssl_mode, PgSslMode::VerifyFull);\n\n    let config = TlsConfig {\n        accept_invalid_certs,\n        accept_invalid_hostnames,\n        hostname: &options.host,\n        root_cert_path: options.ssl_root_cert.as_ref(),\n        client_cert_path: options.ssl_client_cert.as_ref(),\n        client_key_path: options.ssl_client_key.as_ref(),\n    };\n\n    tls::handshake(socket, config, SocketIntoBox).await\n}\n\nasync fn request_upgrade(\n    socket: &mut impl Socket,\n    _options: &PgConnectOptions,\n) -> Result<bool, Error> {\n    // https://www.postgresql.org/docs/current/protocol-flow.html#id-1.10.5.7.11\n\n    // To initiate an SSL-encrypted connection, the frontend initially sends an\n    // SSLRequest message rather than a StartupMessage\n\n    socket.write(SslRequest::BYTES).await?;\n\n    // The server then responds with a single byte containing S or N, indicating that\n    // it is willing or unwilling to perform SSL, respectively.\n\n    let mut response = [0u8];\n\n    socket.read(&mut &mut response[..]).await?;\n\n    match response[0] {\n        b'S' => {\n            // The server is ready and willing to accept an SSL connection\n            Ok(true)\n        }\n\n        b'N' => {\n            // The server is _unwilling_ to perform SSL\n            Ok(false)\n        }\n\n        other => Err(err_protocol!(\n            \"unexpected response from SSLRequest: 0x{:02x}\",\n            other\n        )),\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/copy.rs",
    "content": "use std::borrow::Cow;\nuse std::future::Future;\nuse std::ops::{Deref, DerefMut};\n\nuse futures_core::stream::BoxStream;\n\nuse sqlx_core::bytes::{BufMut, Bytes};\n\nuse crate::connection::PgConnection;\nuse crate::error::{Error, Result};\nuse crate::ext::async_stream::TryAsyncStream;\nuse crate::io::AsyncRead;\nuse crate::message::{\n    BackendMessageFormat, CommandComplete, CopyData, CopyDone, CopyFail, CopyInResponse,\n    CopyOutResponse, CopyResponseData, Query, ReadyForQuery,\n};\nuse crate::pool::{Pool, PoolConnection};\nuse crate::Postgres;\n\nimpl PgConnection {\n    /// Issue a `COPY FROM STDIN` statement and transition the connection to streaming data\n    /// to Postgres. This is a more efficient way to import data into Postgres as compared to\n    /// `INSERT` but requires one of a few specific data formats (text/CSV/binary).\n    ///\n    /// If `statement` is anything other than a `COPY ... FROM STDIN ...` command, an error is\n    /// returned.\n    ///\n    /// Command examples and accepted formats for `COPY` data are shown here:\n    /// <https://www.postgresql.org/docs/current/sql-copy.html>\n    ///\n    /// ### Note\n    /// [PgCopyIn::finish] or [PgCopyIn::abort] *must* be called when finished or the connection\n    /// will return an error the next time it is used.\n    pub async fn copy_in_raw(&mut self, statement: &str) -> Result<PgCopyIn<&mut Self>> {\n        PgCopyIn::begin(self, statement).await\n    }\n\n    /// Issue a `COPY TO STDOUT` statement and transition the connection to streaming data\n    /// from Postgres. This is a more efficient way to export data from Postgres but\n    /// arrives in chunks of one of a few data formats (text/CSV/binary).\n    ///\n    /// If `statement` is anything other than a `COPY ... TO STDOUT ...` command,\n    /// an error is returned.\n    ///\n    /// Note that once this process has begun, unless you read the stream to completion,\n    /// it can only be canceled in two ways:\n    ///\n    /// 1. by closing the connection, or:\n    /// 2. by using another connection to kill the server process that is sending the data as shown\n    ///    [in this StackOverflow answer](https://stackoverflow.com/a/35319598).\n    ///\n    /// If you don't read the stream to completion, the next time the connection is used it will\n    /// need to read and discard all the remaining queued data, which could take some time.\n    ///\n    /// Command examples and accepted formats for `COPY` data are shown here:\n    /// <https://www.postgresql.org/docs/current/sql-copy.html>\n    #[allow(clippy::needless_lifetimes)]\n    pub async fn copy_out_raw<'c>(\n        &'c mut self,\n        statement: &str,\n    ) -> Result<BoxStream<'c, Result<Bytes>>> {\n        pg_begin_copy_out(self, statement).await\n    }\n}\n\n/// Implements methods for directly executing `COPY FROM/TO STDOUT` on a [`PgPool`][crate::PgPool].\n///\n/// This is a replacement for the inherent methods on `PgPool` which could not exist\n/// once the Postgres driver was moved out into its own crate.\npub trait PgPoolCopyExt {\n    /// Issue a `COPY FROM STDIN` statement and begin streaming data to Postgres.\n    /// This is a more efficient way to import data into Postgres as compared to\n    /// `INSERT` but requires one of a few specific data formats (text/CSV/binary).\n    ///\n    /// A single connection will be checked out for the duration.\n    ///\n    /// If `statement` is anything other than a `COPY ... FROM STDIN ...` command, an error is\n    /// returned.\n    ///\n    /// Command examples and accepted formats for `COPY` data are shown here:\n    /// <https://www.postgresql.org/docs/current/sql-copy.html>\n    ///\n    /// ### Note\n    /// [PgCopyIn::finish] or [PgCopyIn::abort] *must* be called when finished or the connection\n    /// will return an error the next time it is used.\n    fn copy_in_raw<'a>(\n        &'a self,\n        statement: &'a str,\n    ) -> impl Future<Output = Result<PgCopyIn<PoolConnection<Postgres>>>> + Send + 'a;\n\n    /// Issue a `COPY TO STDOUT` statement and begin streaming data\n    /// from Postgres. This is a more efficient way to export data from Postgres but\n    /// arrives in chunks of one of a few data formats (text/CSV/binary).\n    ///\n    /// If `statement` is anything other than a `COPY ... TO STDOUT ...` command,\n    /// an error is returned.\n    ///\n    /// Note that once this process has begun, unless you read the stream to completion,\n    /// it can only be canceled in two ways:\n    ///\n    /// 1. by closing the connection, or:\n    /// 2. by using another connection to kill the server process that is sending the data as shown\n    ///    [in this StackOverflow answer](https://stackoverflow.com/a/35319598).\n    ///\n    /// If you don't read the stream to completion, the next time the connection is used it will\n    /// need to read and discard all the remaining queued data, which could take some time.\n    ///\n    /// Command examples and accepted formats for `COPY` data are shown here:\n    /// <https://www.postgresql.org/docs/current/sql-copy.html>\n    fn copy_out_raw<'a>(\n        &'a self,\n        statement: &'a str,\n    ) -> impl Future<Output = Result<BoxStream<'static, Result<Bytes>>>> + Send + 'a;\n}\n\nimpl PgPoolCopyExt for Pool<Postgres> {\n    async fn copy_in_raw<'a>(\n        &'a self,\n        statement: &'a str,\n    ) -> Result<PgCopyIn<PoolConnection<Postgres>>> {\n        PgCopyIn::begin(self.acquire().await?, statement).await\n    }\n\n    async fn copy_out_raw<'a>(\n        &'a self,\n        statement: &'a str,\n    ) -> Result<BoxStream<'static, Result<Bytes>>> {\n        pg_begin_copy_out(self.acquire().await?, statement).await\n    }\n}\n\n// (1 GiB - 1) - 1 - length prefix (4 bytes)\npub const PG_COPY_MAX_DATA_LEN: usize = 0x3fffffff - 1 - 4;\n\n/// A connection in streaming `COPY FROM STDIN` mode.\n///\n/// Created by [PgConnection::copy_in_raw] or [Pool::copy_out_raw].\n///\n/// ### Note\n/// [PgCopyIn::finish] or [PgCopyIn::abort] *must* be called when finished or the connection\n/// will return an error the next time it is used.\n#[must_use = \"connection will error on next use if `.finish()` or `.abort()` is not called\"]\npub struct PgCopyIn<C: DerefMut<Target = PgConnection>> {\n    conn: Option<C>,\n    response: CopyResponseData,\n}\n\nimpl<C: DerefMut<Target = PgConnection>> PgCopyIn<C> {\n    async fn begin(mut conn: C, statement: &str) -> Result<Self> {\n        conn.wait_until_ready().await?;\n        conn.inner.stream.send(Query(statement)).await?;\n\n        let response = match conn.inner.stream.recv_expect::<CopyInResponse>().await {\n            Ok(res) => res.0,\n            Err(e) => {\n                conn.inner.stream.recv().await?;\n                return Err(e);\n            }\n        };\n\n        Ok(PgCopyIn {\n            conn: Some(conn),\n            response,\n        })\n    }\n\n    /// Returns `true` if Postgres is expecting data in text or CSV format.\n    pub fn is_textual(&self) -> bool {\n        self.response.format == 0\n    }\n\n    /// Returns the number of columns expected in the input.\n    pub fn num_columns(&self) -> usize {\n        assert_eq!(\n            self.response.num_columns.unsigned_abs() as usize,\n            self.response.format_codes.len(),\n            \"num_columns does not match format_codes.len()\"\n        );\n        self.response.format_codes.len()\n    }\n\n    /// Check if a column is expecting data in text format (`true`) or binary format (`false`).\n    ///\n    /// ### Panics\n    /// If `column` is out of range according to [`.num_columns()`][Self::num_columns].\n    pub fn column_is_textual(&self, column: usize) -> bool {\n        self.response.format_codes[column] == 0\n    }\n\n    /// Send a chunk of `COPY` data.\n    ///\n    /// The data is sent in chunks if it exceeds the maximum length of a `CopyData` message (1 GiB - 6\n    /// bytes) and may be partially sent if this call is cancelled.\n    ///\n    /// If you're copying data from an `AsyncRead`, maybe consider [Self::read_from] instead.\n    pub async fn send(&mut self, data: impl Deref<Target = [u8]>) -> Result<&mut Self> {\n        for chunk in data.deref().chunks(PG_COPY_MAX_DATA_LEN) {\n            self.conn\n                .as_deref_mut()\n                .expect(\"send_data: conn taken\")\n                .inner\n                .stream\n                .send(CopyData(chunk))\n                .await?;\n        }\n\n        Ok(self)\n    }\n\n    /// Copy data directly from `source` to the database without requiring an intermediate buffer.\n    ///\n    /// `source` will be read to the end.\n    ///\n    /// ### Note: Completion Step Required\n    /// You must still call either [Self::finish] or [Self::abort] to complete the process.\n    ///\n    /// ### Note: Runtime Features\n    /// This method uses the `AsyncRead` trait which is re-exported from either Tokio or `async-std`\n    /// depending on which runtime feature is used.\n    ///\n    /// The runtime features _used_ to be mutually exclusive, but are no longer.\n    /// If both `runtime-async-std` and `runtime-tokio` features are enabled, the Tokio version\n    /// takes precedent.\n    pub async fn read_from(&mut self, mut source: impl AsyncRead + Unpin) -> Result<&mut Self> {\n        let conn: &mut PgConnection = self.conn.as_deref_mut().expect(\"copy_from: conn taken\");\n        loop {\n            let buf = conn.inner.stream.write_buffer_mut();\n\n            // Write the CopyData format code and reserve space for the length.\n            // This may end up sending an empty `CopyData` packet if, after this point,\n            // we get canceled or read 0 bytes, but that should be fine.\n            buf.put_slice(b\"d\\0\\0\\0\\x04\");\n\n            let read = buf.read_from(&mut source).await?;\n\n            if read == 0 {\n                break;\n            }\n\n            // Write the length\n            let read32 = i32::try_from(read)\n                .map_err(|_| err_protocol!(\"number of bytes read exceeds 2^31 - 1: {}\", read))?;\n\n            (&mut buf.get_mut()[1..]).put_i32(read32 + 4);\n\n            conn.inner.stream.flush().await?;\n        }\n\n        Ok(self)\n    }\n\n    /// Signal that the `COPY` process should be aborted and any data received should be discarded.\n    ///\n    /// The given message can be used for indicating the reason for the abort in the database logs.\n    ///\n    /// The server is expected to respond with an error, so only _unexpected_ errors are returned.\n    pub async fn abort(mut self, msg: impl Into<String>) -> Result<()> {\n        let mut conn = self\n            .conn\n            .take()\n            .expect(\"PgCopyIn::fail_with: conn taken illegally\");\n\n        conn.inner.stream.send(CopyFail::new(msg)).await?;\n\n        match conn.inner.stream.recv().await {\n            Ok(msg) => Err(err_protocol!(\n                \"fail_with: expected ErrorResponse, got: {:?}\",\n                msg.format\n            )),\n            Err(Error::Database(e)) => {\n                match e.code() {\n                    Some(Cow::Borrowed(\"57014\")) => {\n                        // postgres abort received error code\n                        conn.inner.stream.recv_expect::<ReadyForQuery>().await?;\n                        Ok(())\n                    }\n                    _ => Err(Error::Database(e)),\n                }\n            }\n            Err(e) => Err(e),\n        }\n    }\n\n    /// Signal that the `COPY` process is complete.\n    ///\n    /// The number of rows affected is returned.\n    pub async fn finish(mut self) -> Result<u64> {\n        let mut conn = self\n            .conn\n            .take()\n            .expect(\"CopyWriter::finish: conn taken illegally\");\n\n        conn.inner.stream.send(CopyDone).await?;\n        let cc: CommandComplete = match conn.inner.stream.recv_expect().await {\n            Ok(cc) => cc,\n            Err(e) => {\n                conn.inner.stream.recv().await?;\n                return Err(e);\n            }\n        };\n\n        conn.inner.stream.recv_expect::<ReadyForQuery>().await?;\n\n        Ok(cc.rows_affected())\n    }\n}\n\nimpl<C: DerefMut<Target = PgConnection>> Drop for PgCopyIn<C> {\n    fn drop(&mut self) {\n        if let Some(mut conn) = self.conn.take() {\n            conn.inner\n                .stream\n                .write_msg(CopyFail::new(\n                    \"PgCopyIn dropped without calling finish() or fail()\",\n                ))\n                .expect(\"BUG: PgCopyIn abort message should not be too large\");\n        }\n    }\n}\n\nasync fn pg_begin_copy_out<'c, C: DerefMut<Target = PgConnection> + Send + 'c>(\n    mut conn: C,\n    statement: &str,\n) -> Result<BoxStream<'c, Result<Bytes>>> {\n    conn.wait_until_ready().await?;\n    conn.inner.stream.send(Query(statement)).await?;\n\n    let _: CopyOutResponse = conn.inner.stream.recv_expect().await?;\n\n    let stream: TryAsyncStream<'c, Bytes> = try_stream! {\n        loop {\n            match conn.inner.stream.recv().await {\n                Err(e) => {\n                    conn.inner.stream.recv_expect::<ReadyForQuery>().await?;\n                    return Err(e);\n                },\n                Ok(msg) => match msg.format {\n                    BackendMessageFormat::CopyData => r#yield!(msg.decode::<CopyData<Bytes>>()?.0),\n                    BackendMessageFormat::CopyDone => {\n                        let _ = msg.decode::<CopyDone>()?;\n                        conn.inner.stream.recv_expect::<CommandComplete>().await?;\n                        conn.inner.stream.recv_expect::<ReadyForQuery>().await?;\n                        return Ok(())\n                    },\n                    _ => return Err(err_protocol!(\"unexpected message format during copy out: {:?}\", msg.format))\n                }\n            }\n        }\n    };\n\n    Ok(Box::pin(stream))\n}\n"
  },
  {
    "path": "sqlx-postgres/src/database.rs",
    "content": "use crate::arguments::PgArgumentBuffer;\nuse crate::value::{PgValue, PgValueRef};\nuse crate::{\n    PgArguments, PgColumn, PgConnection, PgQueryResult, PgRow, PgStatement, PgTransactionManager,\n    PgTypeInfo,\n};\n\npub(crate) use sqlx_core::database::{Database, HasStatementCache};\n\n/// PostgreSQL database driver.\n#[derive(Debug)]\npub struct Postgres;\n\nimpl Database for Postgres {\n    type Connection = PgConnection;\n\n    type TransactionManager = PgTransactionManager;\n\n    type Row = PgRow;\n\n    type QueryResult = PgQueryResult;\n\n    type Column = PgColumn;\n\n    type TypeInfo = PgTypeInfo;\n\n    type Value = PgValue;\n    type ValueRef<'r> = PgValueRef<'r>;\n\n    type Arguments = PgArguments;\n    type ArgumentBuffer = PgArgumentBuffer;\n\n    type Statement = PgStatement;\n\n    const NAME: &'static str = \"PostgreSQL\";\n\n    const URL_SCHEMES: &'static [&'static str] = &[\"postgres\", \"postgresql\"];\n}\n\nimpl HasStatementCache for Postgres {}\n"
  },
  {
    "path": "sqlx-postgres/src/error.rs",
    "content": "use std::error::Error as StdError;\nuse std::fmt::{self, Debug, Display, Formatter};\n\nuse atoi::atoi;\nuse smallvec::alloc::borrow::Cow;\nuse sqlx_core::bytes::Bytes;\npub(crate) use sqlx_core::error::*;\n\nuse crate::message::{BackendMessage, BackendMessageFormat, Notice, PgSeverity};\n\n/// An error returned from the PostgreSQL database.\npub struct PgDatabaseError(pub(crate) Notice);\n\n// Error message fields are documented:\n// https://www.postgresql.org/docs/current/protocol-error-fields.html\n\nimpl PgDatabaseError {\n    #[inline]\n    pub fn severity(&self) -> PgSeverity {\n        self.0.severity()\n    }\n\n    /// The [SQLSTATE](https://www.postgresql.org/docs/current/errcodes-appendix.html) code for\n    /// this error.\n    #[inline]\n    pub fn code(&self) -> &str {\n        self.0.code()\n    }\n\n    /// The primary human-readable error message. This should be accurate but\n    /// terse (typically one line).\n    #[inline]\n    pub fn message(&self) -> &str {\n        self.0.message()\n    }\n\n    /// An optional secondary error message carrying more detail about the problem.\n    /// Might run to multiple lines.\n    #[inline]\n    pub fn detail(&self) -> Option<&str> {\n        self.0.get(b'D')\n    }\n\n    /// An optional suggestion what to do about the problem. This is intended to differ from\n    /// `detail` in that it offers advice (potentially inappropriate) rather than hard facts.\n    /// Might run to multiple lines.\n    #[inline]\n    pub fn hint(&self) -> Option<&str> {\n        self.0.get(b'H')\n    }\n\n    /// Indicates an error cursor position as an index into the original query string; or,\n    /// a position into an internally generated query.\n    #[inline]\n    pub fn position(&self) -> Option<PgErrorPosition<'_>> {\n        self.0\n            .get_raw(b'P')\n            .and_then(atoi)\n            .map(PgErrorPosition::Original)\n            .or_else(|| {\n                let position = self.0.get_raw(b'p').and_then(atoi)?;\n                let query = self.0.get(b'q')?;\n\n                Some(PgErrorPosition::Internal { position, query })\n            })\n    }\n\n    /// An indication of the context in which the error occurred. Presently this includes a call\n    /// stack traceback of active procedural language functions and internally-generated queries.\n    /// The trace is one entry per line, most recent first.\n    pub fn r#where(&self) -> Option<&str> {\n        self.0.get(b'W')\n    }\n\n    /// If this error is with a specific database object, the\n    /// name of the schema containing that object, if any.\n    pub fn schema(&self) -> Option<&str> {\n        self.0.get(b's')\n    }\n\n    /// If this error is with a specific table, the name of the table.\n    pub fn table(&self) -> Option<&str> {\n        self.0.get(b't')\n    }\n\n    /// If the error is with a specific table column, the name of the column.\n    pub fn column(&self) -> Option<&str> {\n        self.0.get(b'c')\n    }\n\n    /// If the error is with a specific data type, the name of the data type.\n    pub fn data_type(&self) -> Option<&str> {\n        self.0.get(b'd')\n    }\n\n    /// If the error is with a specific constraint, the name of the constraint.\n    /// For this purpose, indexes are constraints, even if they weren't created\n    /// with constraint syntax.\n    pub fn constraint(&self) -> Option<&str> {\n        self.0.get(b'n')\n    }\n\n    /// The file name of the source-code location where this error was reported.\n    pub fn file(&self) -> Option<&str> {\n        self.0.get(b'F')\n    }\n\n    /// The line number of the source-code location where this error was reported.\n    pub fn line(&self) -> Option<usize> {\n        self.0.get_raw(b'L').and_then(atoi)\n    }\n\n    /// The name of the source-code routine reporting this error.\n    pub fn routine(&self) -> Option<&str> {\n        self.0.get(b'R')\n    }\n}\n\n#[derive(Debug, Eq, PartialEq)]\npub enum PgErrorPosition<'a> {\n    /// A position (in characters) into the original query.\n    Original(usize),\n\n    /// A position into the internally-generated query.\n    Internal {\n        /// The position in characters.\n        position: usize,\n\n        /// The text of a failed internally-generated command. This could be, for example,\n        /// the SQL query issued by a PL/pgSQL function.\n        query: &'a str,\n    },\n}\n\nimpl Debug for PgDatabaseError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"PgDatabaseError\")\n            .field(\"severity\", &self.severity())\n            .field(\"code\", &self.code())\n            .field(\"message\", &self.message())\n            .field(\"detail\", &self.detail())\n            .field(\"hint\", &self.hint())\n            .field(\"position\", &self.position())\n            .field(\"where\", &self.r#where())\n            .field(\"schema\", &self.schema())\n            .field(\"table\", &self.table())\n            .field(\"column\", &self.column())\n            .field(\"data_type\", &self.data_type())\n            .field(\"constraint\", &self.constraint())\n            .field(\"file\", &self.file())\n            .field(\"line\", &self.line())\n            .field(\"routine\", &self.routine())\n            .finish()\n    }\n}\n\nimpl Display for PgDatabaseError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.write_str(self.message())\n    }\n}\n\nimpl StdError for PgDatabaseError {}\n\nimpl DatabaseError for PgDatabaseError {\n    fn message(&self) -> &str {\n        self.message()\n    }\n\n    fn code(&self) -> Option<Cow<'_, str>> {\n        Some(Cow::Borrowed(self.code()))\n    }\n\n    #[doc(hidden)]\n    fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {\n        self\n    }\n\n    #[doc(hidden)]\n    fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {\n        self\n    }\n\n    #[doc(hidden)]\n    fn into_error(self: Box<Self>) -> BoxDynError {\n        self\n    }\n\n    fn is_transient_in_connect_phase(&self) -> bool {\n        // https://www.postgresql.org/docs/current/errcodes-appendix.html\n        [\n            // too_many_connections\n            // This may be returned if we just un-gracefully closed a connection,\n            // give the database a chance to notice it and clean it up.\n            \"53300\",\n            // cannot_connect_now\n            // Returned if the database is still starting up.\n            \"57P03\",\n        ]\n        .contains(&self.code())\n    }\n\n    fn constraint(&self) -> Option<&str> {\n        self.constraint()\n    }\n\n    fn table(&self) -> Option<&str> {\n        self.table()\n    }\n\n    fn kind(&self) -> ErrorKind {\n        match self.code() {\n            error_codes::UNIQUE_VIOLATION => ErrorKind::UniqueViolation,\n            error_codes::FOREIGN_KEY_VIOLATION => ErrorKind::ForeignKeyViolation,\n            error_codes::NOT_NULL_VIOLATION => ErrorKind::NotNullViolation,\n            error_codes::CHECK_VIOLATION => ErrorKind::CheckViolation,\n            error_codes::EXCLUSION_VIOLATION => ErrorKind::ExclusionViolation,\n            _ => ErrorKind::Other,\n        }\n    }\n}\n\n// ErrorResponse is the same structure as NoticeResponse but a different format code.\nimpl BackendMessage for PgDatabaseError {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::ErrorResponse;\n\n    #[inline(always)]\n    fn decode_body(buf: Bytes) -> std::result::Result<Self, Error> {\n        Ok(Self(Notice::decode_body(buf)?))\n    }\n}\n\n/// For reference: <https://www.postgresql.org/docs/current/errcodes-appendix.html>\npub(crate) mod error_codes {\n    /// Caused when a unique or primary key is violated.\n    pub const UNIQUE_VIOLATION: &str = \"23505\";\n    /// Caused when a foreign key is violated.\n    pub const FOREIGN_KEY_VIOLATION: &str = \"23503\";\n    /// Caused when a column marked as NOT NULL received a null value.\n    pub const NOT_NULL_VIOLATION: &str = \"23502\";\n    /// Caused when a check constraint is violated.\n    pub const CHECK_VIOLATION: &str = \"23514\";\n    /// Caused when a exclude constraint is violated.\n    pub const EXCLUSION_VIOLATION: &str = \"23P01\";\n}\n"
  },
  {
    "path": "sqlx-postgres/src/io/buf_mut.rs",
    "content": "use crate::io::{PortalId, StatementId};\n\npub trait PgBufMutExt {\n    fn put_length_prefixed<F>(&mut self, f: F) -> Result<(), crate::Error>\n    where\n        F: FnOnce(&mut Vec<u8>) -> Result<(), crate::Error>;\n\n    fn put_statement_name(&mut self, id: StatementId);\n\n    fn put_portal_name(&mut self, id: PortalId);\n}\n\nimpl PgBufMutExt for Vec<u8> {\n    // writes a length-prefixed message, this is used when encoding nearly all messages as postgres\n    // wants us to send the length of the often-variable-sized messages up front\n    fn put_length_prefixed<F>(&mut self, write_contents: F) -> Result<(), crate::Error>\n    where\n        F: FnOnce(&mut Vec<u8>) -> Result<(), crate::Error>,\n    {\n        // reserve space to write the prefixed length\n        let offset = self.len();\n        self.extend(&[0; 4]);\n\n        // write the main body of the message\n        let write_result = write_contents(self);\n\n        let size_result = write_result.and_then(|_| {\n            let size = self.len() - offset;\n            i32::try_from(size)\n                .map_err(|_| err_protocol!(\"message size out of range for protocol: {size}\"))\n        });\n\n        match size_result {\n            Ok(size) => {\n                // now calculate the size of what we wrote and set the length value\n                self[offset..(offset + 4)].copy_from_slice(&size.to_be_bytes());\n                Ok(())\n            }\n            Err(e) => {\n                // Put the buffer back to where it was.\n                self.truncate(offset);\n                Err(e)\n            }\n        }\n    }\n\n    // writes a statement name by ID\n    #[inline]\n    fn put_statement_name(&mut self, id: StatementId) {\n        id.put_name_with_nul(self);\n    }\n\n    // writes a portal name by ID\n    #[inline]\n    fn put_portal_name(&mut self, id: PortalId) {\n        id.put_name_with_nul(self);\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/io/mod.rs",
    "content": "mod buf_mut;\n\npub use buf_mut::PgBufMutExt;\nuse std::fmt;\nuse std::fmt::{Display, Formatter};\nuse std::num::{NonZeroU32, Saturating};\n\npub(crate) use sqlx_core::io::*;\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub(crate) struct StatementId(IdInner);\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\npub(crate) struct PortalId(IdInner);\n\n#[derive(Debug, Copy, Clone, PartialEq, Eq)]\nstruct IdInner(Option<NonZeroU32>);\n\n#[allow(unused)]\npub(crate) struct DisplayId {\n    prefix: &'static str,\n    id: NonZeroU32,\n}\n\nimpl StatementId {\n    #[allow(dead_code)]\n    pub const UNNAMED: Self = Self(IdInner::UNNAMED);\n\n    pub const NAMED_START: Self = Self(IdInner::NAMED_START);\n\n    #[cfg(test)]\n    pub const TEST_VAL: Self = Self(IdInner::TEST_VAL);\n\n    const NAME_PREFIX: &'static str = \"sqlx_s_\";\n\n    pub fn next(&self) -> Self {\n        Self(self.0.next())\n    }\n\n    pub fn name_len(&self) -> Saturating<usize> {\n        self.0.name_len(Self::NAME_PREFIX)\n    }\n\n    /// Get a type to format this statement ID with [`Display`].\n    ///\n    /// Returns `None` if this is the unnamed statement.\n    #[allow(unused)]\n    #[inline(always)]\n    pub fn display(&self) -> Option<DisplayId> {\n        self.0.display(Self::NAME_PREFIX)\n    }\n\n    pub fn put_name_with_nul(&self, buf: &mut Vec<u8>) {\n        self.0.put_name_with_nul(Self::NAME_PREFIX, buf)\n    }\n}\n\nimpl Display for DisplayId {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}{}\", self.prefix, self.id)\n    }\n}\n\n#[allow(dead_code)]\nimpl PortalId {\n    // None selects the unnamed portal\n    pub const UNNAMED: Self = PortalId(IdInner::UNNAMED);\n\n    pub const NAMED_START: Self = PortalId(IdInner::NAMED_START);\n\n    #[cfg(test)]\n    pub const TEST_VAL: Self = Self(IdInner::TEST_VAL);\n\n    const NAME_PREFIX: &'static str = \"sqlx_p_\";\n\n    /// If ID represents a named portal, return the next ID, wrapping on overflow.\n    ///\n    /// If this ID represents the unnamed portal, return the same.\n    pub fn next(&self) -> Self {\n        Self(self.0.next())\n    }\n\n    /// Calculate the number of bytes that will be written by [`Self::put_name_with_nul()`].\n    pub fn name_len(&self) -> Saturating<usize> {\n        self.0.name_len(Self::NAME_PREFIX)\n    }\n\n    pub fn put_name_with_nul(&self, buf: &mut Vec<u8>) {\n        self.0.put_name_with_nul(Self::NAME_PREFIX, buf)\n    }\n}\n\nimpl IdInner {\n    const UNNAMED: Self = Self(None);\n\n    const NAMED_START: Self = Self(Some(NonZeroU32::MIN));\n\n    #[cfg(test)]\n    pub const TEST_VAL: Self = Self(NonZeroU32::new(1234567890));\n\n    #[inline(always)]\n    fn next(&self) -> Self {\n        Self(\n            self.0\n                .map(|id| id.checked_add(1).unwrap_or(NonZeroU32::MIN)),\n        )\n    }\n\n    #[allow(unused)]\n    #[inline(always)]\n    fn display(&self, prefix: &'static str) -> Option<DisplayId> {\n        self.0.map(|id| DisplayId { prefix, id })\n    }\n\n    #[inline(always)]\n    fn name_len(&self, name_prefix: &str) -> Saturating<usize> {\n        let mut len = Saturating(0);\n\n        if let Some(id) = self.0 {\n            len += name_prefix.len();\n            // estimate the length of the ID in decimal\n            // `.ilog10()` can't panic since the value is never zero\n            len += id.get().ilog10() as usize;\n            // add one to compensate for `ilog10()` rounding down.\n            len += 1;\n        }\n\n        // count the NUL terminator\n        len += 1;\n\n        len\n    }\n\n    #[inline(always)]\n    fn put_name_with_nul(&self, name_prefix: &str, buf: &mut Vec<u8>) {\n        if let Some(id) = self.0 {\n            buf.extend_from_slice(name_prefix.as_bytes());\n            buf.extend_from_slice(itoa::Buffer::new().format(id.get()).as_bytes());\n        }\n\n        buf.push(0);\n    }\n}\n\n#[test]\nfn statement_id_display_matches_encoding() {\n    const EXPECTED_STR: &str = \"sqlx_s_1234567890\";\n    const EXPECTED_BYTES: &[u8] = b\"sqlx_s_1234567890\\0\";\n\n    let mut bytes = Vec::new();\n\n    StatementId::TEST_VAL.put_name_with_nul(&mut bytes);\n\n    assert_eq!(bytes, EXPECTED_BYTES);\n\n    let str = StatementId::TEST_VAL.display().unwrap().to_string();\n\n    assert_eq!(str, EXPECTED_STR);\n}\n"
  },
  {
    "path": "sqlx-postgres/src/lib.rs",
    "content": "//! **PostgreSQL** database driver.\n\n#[macro_use]\nextern crate sqlx_core;\n\nuse crate::executor::Executor;\n\nmod advisory_lock;\nmod arguments;\nmod bind_iter;\nmod column;\nmod connection;\nmod copy;\nmod database;\nmod error;\nmod io;\nmod listener;\nmod message;\nmod options;\nmod query_result;\nmod row;\nmod statement;\nmod transaction;\nmod type_checking;\nmod type_info;\npub mod types;\nmod value;\n\n#[cfg(feature = \"any\")]\n// We are hiding the any module with its AnyConnectionBackend trait\n// so that IDEs don't show it in the autocompletion list\n// and end users don't accidentally use it. This can result in\n// nested transactions not behaving as expected.\n// For more information, see https://github.com/launchbadge/sqlx/pull/3254#issuecomment-2144043823\n#[doc(hidden)]\npub mod any;\n\n#[doc(hidden)]\npub use copy::PG_COPY_MAX_DATA_LEN;\n\n#[cfg(feature = \"migrate\")]\nmod migrate;\n\n#[cfg(feature = \"migrate\")]\nmod testing;\n\npub(crate) use sqlx_core::driver_prelude::*;\n\npub use advisory_lock::{PgAdvisoryLock, PgAdvisoryLockGuard, PgAdvisoryLockKey};\npub use arguments::{PgArgumentBuffer, PgArguments};\npub use bind_iter::PgBindIterExt;\npub use column::PgColumn;\npub use connection::PgConnection;\npub use copy::{PgCopyIn, PgPoolCopyExt};\npub use database::Postgres;\npub use error::{PgDatabaseError, PgErrorPosition};\npub use listener::{PgListener, PgNotification};\npub use message::PgSeverity;\npub use options::{PgConnectOptions, PgSslMode};\npub use query_result::PgQueryResult;\npub use row::PgRow;\npub use statement::PgStatement;\npub use transaction::PgTransactionManager;\npub use type_info::{PgTypeInfo, PgTypeKind};\npub use types::PgHasArrayType;\npub use value::{PgValue, PgValueFormat, PgValueRef};\n\n/// An alias for [`Pool`][crate::pool::Pool], specialized for Postgres.\npub type PgPool = crate::pool::Pool<Postgres>;\n\n/// An alias for [`PoolOptions`][crate::pool::PoolOptions], specialized for Postgres.\npub type PgPoolOptions = crate::pool::PoolOptions<Postgres>;\n\n/// An alias for [`Executor<'_, Database = Postgres>`][Executor].\npub trait PgExecutor<'c>: Executor<'c, Database = Postgres> {}\nimpl<'c, T: Executor<'c, Database = Postgres>> PgExecutor<'c> for T {}\n\n/// An alias for [`Transaction`][crate::transaction::Transaction], specialized for Postgres.\npub type PgTransaction<'c> = crate::transaction::Transaction<'c, Postgres>;\n\nimpl_into_arguments_for_arguments!(PgArguments);\nimpl_acquire!(Postgres, PgConnection);\nimpl_column_index_for_row!(PgRow);\nimpl_column_index_for_statement!(PgStatement);\nimpl_encode_for_option!(Postgres);\n"
  },
  {
    "path": "sqlx-postgres/src/listener.rs",
    "content": "use std::fmt::{self, Debug};\nuse std::io;\nuse std::str::from_utf8;\n\nuse futures_channel::mpsc;\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::{BoxStream, Stream};\nuse futures_util::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};\nuse sqlx_core::acquire::Acquire;\nuse sqlx_core::sql_str::{AssertSqlSafe, SqlStr};\nuse sqlx_core::transaction::Transaction;\nuse sqlx_core::Either;\nuse tracing::Instrument;\n\nuse crate::error::Error;\nuse crate::executor::{Execute, Executor};\nuse crate::message::{BackendMessageFormat, Notification};\nuse crate::pool::PoolOptions;\nuse crate::pool::{Pool, PoolConnection};\nuse crate::{PgConnection, PgQueryResult, PgRow, PgStatement, PgTypeInfo, Postgres};\n\n/// A stream of asynchronous notifications from Postgres.\n///\n/// This listener will auto-reconnect. If the active\n/// connection being used ever dies, this listener will detect that event, create a\n/// new connection, will re-subscribe to all of the originally specified channels, and will resume\n/// operations as normal.\npub struct PgListener {\n    pool: Pool<Postgres>,\n    connection: Option<PoolConnection<Postgres>>,\n    buffer_rx: mpsc::UnboundedReceiver<Notification>,\n    buffer_tx: Option<mpsc::UnboundedSender<Notification>>,\n    channels: Vec<String>,\n    ignore_close_event: bool,\n    eager_reconnect: bool,\n}\n\n/// An asynchronous notification from Postgres.\npub struct PgNotification(Notification);\n\nimpl PgListener {\n    pub async fn connect(url: &str) -> Result<Self, Error> {\n        // Create a pool of 1 without timeouts (as they don't apply here)\n        // We only use the pool to handle re-connections\n        let pool = PoolOptions::<Postgres>::new()\n            .max_connections(1)\n            .max_lifetime(None)\n            .idle_timeout(None)\n            .connect(url)\n            .await?;\n\n        let mut this = Self::connect_with(&pool).await?;\n        // We don't need to handle close events\n        this.ignore_close_event = true;\n\n        Ok(this)\n    }\n\n    pub async fn connect_with(pool: &Pool<Postgres>) -> Result<Self, Error> {\n        // Pull out an initial connection\n        let mut connection = pool.acquire().await?;\n\n        // Setup a notification buffer\n        let (sender, receiver) = mpsc::unbounded();\n        connection.inner.stream.notifications = Some(sender);\n\n        Ok(Self {\n            pool: pool.clone(),\n            connection: Some(connection),\n            buffer_rx: receiver,\n            buffer_tx: None,\n            channels: Vec::new(),\n            ignore_close_event: false,\n            eager_reconnect: true,\n        })\n    }\n\n    /// Set whether or not to ignore [`Pool::close_event()`]. Defaults to `false`.\n    ///\n    /// By default, when [`Pool::close()`] is called on the pool this listener is using\n    /// while [`Self::recv()`] or [`Self::try_recv()`] are waiting for a message, the wait is\n    /// cancelled and `Err(PoolClosed)` is returned.\n    ///\n    /// This is because `Pool::close()` will wait until _all_ connections are returned and closed,\n    /// including the one being used by this listener.\n    ///\n    /// Otherwise, `pool.close().await` would have to wait until `PgListener` encountered a\n    /// need to acquire a new connection (timeout, error, etc.) and dropped the one it was\n    /// currently holding, at which point `.recv()` or `.try_recv()` would return `Err(PoolClosed)`\n    /// on the attempt to acquire a new connection anyway.\n    ///\n    /// However, if you want `PgListener` to ignore the close event and continue waiting for a\n    /// message as long as it can, set this to `true`.\n    ///\n    /// Does nothing if this was constructed with [`PgListener::connect()`], as that creates an\n    /// internal pool just for the new instance of `PgListener` which cannot be closed manually.\n    pub fn ignore_pool_close_event(&mut self, val: bool) {\n        self.ignore_close_event = val;\n    }\n\n    /// Set whether a lost connection in `try_recv()` should be re-established before it returns\n    /// `Ok(None)`, or on the next call to `try_recv()`.\n    ///\n    /// By default, this is `true` and the connection is re-established before returning `Ok(None)`.\n    ///\n    /// If this is set to `false` then notifications will continue to be lost until the next call\n    /// to `try_recv()`. If your recovery logic uses a different database connection then\n    /// notifications that occur after it completes may be lost without any way to tell that they\n    /// have been.\n    pub fn eager_reconnect(&mut self, val: bool) {\n        self.eager_reconnect = val;\n    }\n\n    /// Starts listening for notifications on a channel.\n    /// The channel name is quoted here to ensure case sensitivity.\n    pub async fn listen(&mut self, channel: &str) -> Result<(), Error> {\n        self.connection()\n            .await?\n            .execute(AssertSqlSafe(format!(r#\"LISTEN \"{}\"\"#, ident(channel))))\n            .await?;\n\n        self.channels.push(channel.to_owned());\n\n        Ok(())\n    }\n\n    /// Starts listening for notifications on all channels.\n    pub async fn listen_all(\n        &mut self,\n        channels: impl IntoIterator<Item = &str>,\n    ) -> Result<(), Error> {\n        let beg = self.channels.len();\n        self.channels.extend(channels.into_iter().map(|s| s.into()));\n\n        let query = build_listen_all_query(&self.channels[beg..]);\n        self.connection()\n            .await?\n            .execute(AssertSqlSafe(query))\n            .await?;\n\n        Ok(())\n    }\n\n    /// Stops listening for notifications on a channel.\n    /// The channel name is quoted here to ensure case sensitivity.\n    pub async fn unlisten(&mut self, channel: &str) -> Result<(), Error> {\n        // use RAW connection and do NOT re-connect automatically, since this is not required for\n        // UNLISTEN (we've disconnected anyways)\n        if let Some(connection) = self.connection.as_mut() {\n            connection\n                .execute(AssertSqlSafe(format!(r#\"UNLISTEN \"{}\"\"#, ident(channel))))\n                .await?;\n        }\n\n        if let Some(pos) = self.channels.iter().position(|s| s == channel) {\n            self.channels.remove(pos);\n        }\n\n        Ok(())\n    }\n\n    /// Stops listening for notifications on all channels.\n    pub async fn unlisten_all(&mut self) -> Result<(), Error> {\n        // use RAW connection and do NOT re-connect automatically, since this is not required for\n        // UNLISTEN (we've disconnected anyways)\n        if let Some(connection) = self.connection.as_mut() {\n            connection.execute(\"UNLISTEN *\").await?;\n        }\n\n        self.channels.clear();\n\n        Ok(())\n    }\n\n    #[inline]\n    async fn connect_if_needed(&mut self) -> Result<(), Error> {\n        if self.connection.is_none() {\n            let mut connection = self.pool.acquire().await?;\n            connection.inner.stream.notifications = self.buffer_tx.take();\n\n            connection\n                .execute(AssertSqlSafe(build_listen_all_query(&self.channels)))\n                .await?;\n\n            self.connection = Some(connection);\n        }\n\n        Ok(())\n    }\n\n    #[inline]\n    async fn connection(&mut self) -> Result<&mut PgConnection, Error> {\n        // Ensure we have an active connection to work with.\n        self.connect_if_needed().await?;\n\n        Ok(self.connection.as_mut().unwrap())\n    }\n\n    /// Receives the next notification available from any of the subscribed channels.\n    ///\n    /// If the connection to PostgreSQL is lost, it is automatically reconnected on the next\n    /// call to `recv()`, and should be entirely transparent (as long as it was just an\n    /// intermittent network failure or long-lived connection reaper).\n    ///\n    /// As notifications are transient, any received while the connection was lost, will not\n    /// be returned. If you'd prefer the reconnection to be explicit and have a chance to\n    /// do something before, please see [`try_recv`](Self::try_recv).\n    ///\n    /// # Example\n    ///\n    /// ```rust,no_run\n    /// # use sqlx::postgres::PgListener;\n    /// #\n    /// # sqlx::__rt::test_block_on(async move {\n    /// let mut listener = PgListener::connect(\"postgres:// ...\").await?;\n    /// loop {\n    ///     // ask for next notification, re-connecting (transparently) if needed\n    ///     let notification = listener.recv().await?;\n    ///\n    ///     // handle notification, do something interesting\n    /// }\n    /// # Result::<(), sqlx::Error>::Ok(())\n    /// # }).unwrap();\n    /// ```\n    pub async fn recv(&mut self) -> Result<PgNotification, Error> {\n        loop {\n            if let Some(notification) = self.try_recv().await? {\n                return Ok(notification);\n            }\n        }\n    }\n\n    /// Receives the next notification available from any of the subscribed channels.\n    ///\n    /// If the connection to PostgreSQL is lost, `None` is returned, and the connection is\n    /// reconnected either immediately, or on the next call to `try_recv()`, depending on\n    /// the value of [`eager_reconnect`].\n    ///\n    /// # Example\n    ///\n    /// ```rust,no_run\n    /// # use sqlx::postgres::PgListener;\n    /// #\n    /// # sqlx::__rt::test_block_on(async move {\n    /// # let mut listener = PgListener::connect(\"postgres:// ...\").await?;\n    /// loop {\n    ///     // start handling notifications, connecting if needed\n    ///     while let Some(notification) = listener.try_recv().await? {\n    ///         // handle notification\n    ///     }\n    ///\n    ///     // connection lost, do something interesting\n    /// }\n    /// # Result::<(), sqlx::Error>::Ok(())\n    /// # }).unwrap();\n    /// ```\n    ///\n    /// [`eager_reconnect`]: PgListener::eager_reconnect\n    pub async fn try_recv(&mut self) -> Result<Option<PgNotification>, Error> {\n        // Flush the buffer first, if anything\n        // This would only fill up if this listener is used as a connection\n        if let Some(notification) = self.next_buffered() {\n            return Ok(Some(notification));\n        }\n\n        // Fetch our `CloseEvent` listener, if applicable.\n        let mut close_event = (!self.ignore_close_event).then(|| self.pool.close_event());\n\n        loop {\n            let next_message = self.connection().await?.inner.stream.recv_unchecked();\n\n            let res = if let Some(ref mut close_event) = close_event {\n                // cancels the wait and returns `Err(PoolClosed)` if the pool is closed\n                // before `next_message` returns, or if the pool was already closed\n                close_event.do_until(next_message).await?\n            } else {\n                next_message.await\n            };\n\n            let message = match res {\n                Ok(message) => message,\n\n                // The connection is dead, ensure that it is dropped,\n                // update self state, and loop to try again.\n                Err(Error::Io(err))\n                    if matches!(\n                        err.kind(),\n                        io::ErrorKind::ConnectionAborted |\n                        io::ErrorKind::UnexpectedEof |\n                        // see ERRORS section in tcp(7) man page (https://man7.org/linux/man-pages/man7/tcp.7.html)\n                        io::ErrorKind::TimedOut |\n                        io::ErrorKind::BrokenPipe\n                    ) =>\n                {\n                    if let Some(mut conn) = self.connection.take() {\n                        self.buffer_tx = conn.inner.stream.notifications.take();\n                        // Close the connection in a background task, so we can continue.\n                        conn.close_on_drop();\n                    }\n\n                    if self.eager_reconnect {\n                        self.connect_if_needed().await?;\n                    }\n\n                    // lost connection\n                    return Ok(None);\n                }\n\n                // Forward other errors\n                Err(error) => {\n                    return Err(error);\n                }\n            };\n\n            match message.format {\n                // We've received an async notification, return it.\n                BackendMessageFormat::NotificationResponse => {\n                    return Ok(Some(PgNotification(message.decode()?)));\n                }\n\n                // Mark the connection as ready for another query\n                BackendMessageFormat::ReadyForQuery => {\n                    self.connection().await?.inner.pending_ready_for_query_count -= 1;\n                }\n\n                // Ignore unexpected messages\n                _ => {}\n            }\n        }\n    }\n\n    /// Receives the next notification that already exists in the connection buffer, if any.\n    ///\n    /// This is similar to `try_recv`, except it will not wait if the connection has not yet received a notification.\n    ///\n    /// This is helpful if you want to retrieve all buffered notifications and process them in batches.\n    pub fn next_buffered(&mut self) -> Option<PgNotification> {\n        if let Ok(Some(notification)) = self.buffer_rx.try_next() {\n            Some(PgNotification(notification))\n        } else {\n            None\n        }\n    }\n\n    /// Consume this listener, returning a `Stream` of notifications.\n    ///\n    /// The backing connection will be automatically reconnected should it be lost.\n    ///\n    /// This has the same potential drawbacks as [`recv`](PgListener::recv).\n    ///\n    pub fn into_stream(mut self) -> impl Stream<Item = Result<PgNotification, Error>> + Unpin {\n        Box::pin(try_stream! {\n            loop {\n                r#yield!(self.recv().await?);\n            }\n        })\n    }\n}\n\nimpl Drop for PgListener {\n    fn drop(&mut self) {\n        if let Some(mut conn) = self.connection.take() {\n            let fut = async move {\n                let _ = conn.execute(\"UNLISTEN *\").await;\n\n                // inline the drop handler from `PoolConnection` so it doesn't try to spawn another task\n                // otherwise, it may trigger a panic if this task is dropped because the runtime is going away:\n                // https://github.com/launchbadge/sqlx/issues/1389\n                conn.return_to_pool().await;\n            };\n\n            // Unregister any listeners before returning the connection to the pool.\n            crate::rt::spawn(fut.in_current_span());\n        }\n    }\n}\n\nimpl<'c> Acquire<'c> for &'c mut PgListener {\n    type Database = Postgres;\n    type Connection = &'c mut PgConnection;\n\n    fn acquire(self) -> BoxFuture<'c, Result<Self::Connection, Error>> {\n        self.connection().boxed()\n    }\n\n    fn begin(self) -> BoxFuture<'c, Result<Transaction<'c, Self::Database>, Error>> {\n        self.connection().and_then(|c| c.begin()).boxed()\n    }\n}\n\nimpl<'c> Executor<'c> for &'c mut PgListener {\n    type Database = Postgres;\n\n    fn fetch_many<'e, 'q, E>(\n        self,\n        query: E,\n    ) -> BoxStream<'e, Result<Either<PgQueryResult, PgRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        futures_util::stream::once(async move {\n            // need some basic type annotation to help the compiler a bit\n            let res: Result<_, Error> = Ok(self.connection().await?.fetch_many(query));\n            res\n        })\n        .try_flatten()\n        .boxed()\n    }\n\n    fn fetch_optional<'e, 'q, E>(self, query: E) -> BoxFuture<'e, Result<Option<PgRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        async move { self.connection().await?.fetch_optional(query).await }.boxed()\n    }\n\n    fn prepare_with<'e>(\n        self,\n        query: SqlStr,\n        parameters: &'e [PgTypeInfo],\n    ) -> BoxFuture<'e, Result<PgStatement, Error>>\n    where\n        'c: 'e,\n    {\n        async move {\n            self.connection()\n                .await?\n                .prepare_with(query, parameters)\n                .await\n        }\n        .boxed()\n    }\n\n    #[doc(hidden)]\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        query: SqlStr,\n    ) -> BoxFuture<'e, Result<crate::describe::Describe<Self::Database>, Error>>\n    where\n        'c: 'e,\n    {\n        async move { self.connection().await?.describe(query).await }.boxed()\n    }\n}\n\nimpl PgNotification {\n    /// The process ID of the notifying backend process.\n    #[inline]\n    pub fn process_id(&self) -> u32 {\n        self.0.process_id\n    }\n\n    /// The channel that the notify has been raised on. This can be thought\n    /// of as the message topic.\n    #[inline]\n    pub fn channel(&self) -> &str {\n        from_utf8(&self.0.channel).unwrap()\n    }\n\n    /// The payload of the notification. An empty payload is received as an\n    /// empty string.\n    #[inline]\n    pub fn payload(&self) -> &str {\n        from_utf8(&self.0.payload).unwrap()\n    }\n}\n\nimpl Debug for PgListener {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"PgListener\").finish()\n    }\n}\n\nimpl Debug for PgNotification {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"PgNotification\")\n            .field(\"process_id\", &self.process_id())\n            .field(\"channel\", &self.channel())\n            .field(\"payload\", &self.payload())\n            .finish()\n    }\n}\n\nfn ident(mut name: &str) -> String {\n    // If the input string contains a NUL byte, we should truncate the\n    // identifier.\n    if let Some(index) = name.find('\\0') {\n        name = &name[..index];\n    }\n\n    // Any double quotes must be escaped\n    name.replace('\"', \"\\\"\\\"\")\n}\n\nfn build_listen_all_query(channels: impl IntoIterator<Item = impl AsRef<str>>) -> String {\n    channels.into_iter().fold(String::new(), |mut acc, chan| {\n        acc.push_str(r#\"LISTEN \"\"#);\n        acc.push_str(&ident(chan.as_ref()));\n        acc.push_str(r#\"\";\"#);\n        acc\n    })\n}\n\n#[test]\nfn test_build_listen_all_query_with_single_channel() {\n    let output = build_listen_all_query([\"test\"]);\n    assert_eq!(output.as_str(), r#\"LISTEN \"test\";\"#);\n}\n\n#[test]\nfn test_build_listen_all_query_with_multiple_channels() {\n    let output = build_listen_all_query([\"channel.0\", \"channel.1\"]);\n    assert_eq!(output.as_str(), r#\"LISTEN \"channel.0\";LISTEN \"channel.1\";\"#);\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/authentication.rs",
    "content": "use std::str::from_utf8;\n\nuse memchr::memchr;\nuse sqlx_core::bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::ProtocolDecode;\n\nuse crate::message::{BackendMessage, BackendMessageFormat};\nuse base64::prelude::{Engine as _, BASE64_STANDARD};\n// On startup, the server sends an appropriate authentication request message,\n// to which the frontend must reply with an appropriate authentication\n// response message (such as a password).\n\n// For all authentication methods except GSSAPI, SSPI and SASL, there is at\n// most one request and one response. In some methods, no response at all is\n// needed from the frontend, and so no authentication request occurs.\n\n// For GSSAPI, SSPI and SASL, multiple exchanges of packets may\n// be needed to complete the authentication.\n\n// <https://www.postgresql.org/docs/devel/protocol-flow.html#id-1.10.5.7.3>\n// <https://www.postgresql.org/docs/devel/protocol-message-formats.html>\n\n#[derive(Debug)]\npub enum Authentication {\n    /// The authentication exchange is successfully completed.\n    Ok,\n\n    /// The frontend must now send a [PasswordMessage] containing the\n    /// password in clear-text form.\n    CleartextPassword,\n\n    /// The frontend must now send a [PasswordMessage] containing the\n    /// password (with user name) encrypted via MD5, then encrypted\n    /// again using the 4-byte random salt.\n    Md5Password(AuthenticationMd5Password),\n\n    /// The frontend must now initiate a SASL negotiation,\n    /// using one of the SASL mechanisms listed in the message.\n    ///\n    /// The frontend will send a [SaslInitialResponse] with the name\n    /// of the selected mechanism, and the first part of the SASL\n    /// data stream in response to this.\n    ///\n    /// If further messages are needed, the server will\n    /// respond with [Authentication::SaslContinue].\n    Sasl(AuthenticationSasl),\n\n    /// This message contains challenge data from the previous step of SASL negotiation.\n    ///\n    /// The frontend must respond with a [SaslResponse] message.\n    SaslContinue(AuthenticationSaslContinue),\n\n    /// SASL authentication has completed with additional mechanism-specific\n    /// data for the client.\n    ///\n    /// The server will next send [Authentication::Ok] to\n    /// indicate successful authentication.\n    SaslFinal(AuthenticationSaslFinal),\n}\n\nimpl BackendMessage for Authentication {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::Authentication;\n\n    fn decode_body(mut buf: Bytes) -> Result<Self, Error> {\n        Ok(match buf.get_u32() {\n            0 => Authentication::Ok,\n\n            3 => Authentication::CleartextPassword,\n\n            5 => {\n                let mut salt = [0; 4];\n                buf.copy_to_slice(&mut salt);\n\n                Authentication::Md5Password(AuthenticationMd5Password { salt })\n            }\n\n            10 => Authentication::Sasl(AuthenticationSasl(buf)),\n            11 => Authentication::SaslContinue(AuthenticationSaslContinue::decode(buf)?),\n            12 => Authentication::SaslFinal(AuthenticationSaslFinal::decode(buf)?),\n\n            ty => {\n                return Err(err_protocol!(\"unknown authentication method: {}\", ty));\n            }\n        })\n    }\n}\n\n/// Body of [Authentication::Md5Password].\n#[derive(Debug)]\npub struct AuthenticationMd5Password {\n    pub salt: [u8; 4],\n}\n\n/// Body of [Authentication::Sasl].\n#[derive(Debug)]\npub struct AuthenticationSasl(Bytes);\n\nimpl AuthenticationSasl {\n    #[inline]\n    pub fn mechanisms(&self) -> SaslMechanisms<'_> {\n        SaslMechanisms(&self.0)\n    }\n}\n\n/// An iterator over the SASL authentication mechanisms provided by the server.\npub struct SaslMechanisms<'a>(&'a [u8]);\n\nimpl<'a> Iterator for SaslMechanisms<'a> {\n    type Item = &'a str;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        if !self.0.is_empty() && self.0[0] == b'\\0' {\n            return None;\n        }\n\n        let mechanism = memchr(b'\\0', self.0).and_then(|nul| from_utf8(&self.0[..nul]).ok())?;\n\n        self.0 = &self.0[(mechanism.len() + 1)..];\n\n        Some(mechanism)\n    }\n}\n\n#[derive(Debug)]\npub struct AuthenticationSaslContinue {\n    pub salt: Vec<u8>,\n    pub iterations: u32,\n    pub nonce: String,\n    pub message: String,\n}\n\nimpl ProtocolDecode<'_> for AuthenticationSaslContinue {\n    fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {\n        let mut iterations: u32 = 4096;\n        let mut salt = Vec::new();\n        let mut nonce = Bytes::new();\n\n        // [Example]\n        // r=/z+giZiTxAH7r8sNAeHr7cvpqV3uo7G/bJBIJO3pjVM7t3ng,s=4UV68bIkC8f9/X8xH7aPhg==,i=4096\n\n        for item in buf.split(|b| *b == b',') {\n            let key = item[0];\n            let value = &item[2..];\n\n            match key {\n                b'r' => {\n                    nonce = buf.slice_ref(value);\n                }\n\n                b'i' => {\n                    iterations = atoi::atoi(value).unwrap_or(4096);\n                }\n\n                b's' => {\n                    salt = BASE64_STANDARD.decode(value).map_err(Error::protocol)?;\n                }\n\n                _ => {}\n            }\n        }\n\n        Ok(Self {\n            iterations,\n            salt,\n            nonce: from_utf8(&nonce).map_err(Error::protocol)?.to_owned(),\n            message: from_utf8(&buf).map_err(Error::protocol)?.to_owned(),\n        })\n    }\n}\n\n#[derive(Debug)]\npub struct AuthenticationSaslFinal {\n    pub verifier: Vec<u8>,\n}\n\nimpl ProtocolDecode<'_> for AuthenticationSaslFinal {\n    fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {\n        let mut verifier = Vec::new();\n\n        for item in buf.split(|b| *b == b',') {\n            let key = item[0];\n            let value = &item[2..];\n\n            if let b'v' = key {\n                verifier = BASE64_STANDARD.decode(value).map_err(Error::protocol)?;\n            }\n        }\n\n        Ok(Self { verifier })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/backend_key_data.rs",
    "content": "use byteorder::{BigEndian, ByteOrder};\nuse sqlx_core::bytes::Bytes;\n\nuse crate::error::Error;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n/// Contains cancellation key data. The frontend must save these values if it\n/// wishes to be able to issue `CancelRequest` messages later.\n#[derive(Debug)]\npub struct BackendKeyData {\n    /// The process ID of this database.\n    pub process_id: u32,\n\n    /// The secret key of this database.\n    pub secret_key: u32,\n}\n\nimpl BackendMessage for BackendKeyData {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::BackendKeyData;\n\n    fn decode_body(buf: Bytes) -> Result<Self, Error> {\n        let process_id = BigEndian::read_u32(&buf);\n        let secret_key = BigEndian::read_u32(&buf[4..]);\n\n        Ok(Self {\n            process_id,\n            secret_key,\n        })\n    }\n}\n\n#[test]\nfn test_decode_backend_key_data() {\n    const DATA: &[u8] = b\"\\0\\0'\\xc6\\x89R\\xc5+\";\n\n    let m = BackendKeyData::decode_body(DATA.into()).unwrap();\n\n    assert_eq!(m.process_id, 10182);\n    assert_eq!(m.secret_key, 2303903019);\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_backend_key_data(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"\\0\\0'\\xc6\\x89R\\xc5+\";\n\n    b.iter(|| {\n        BackendKeyData::decode_body(test::black_box(Bytes::from_static(DATA))).unwrap();\n    });\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/bind.rs",
    "content": "use crate::io::{PgBufMutExt, PortalId, StatementId};\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse crate::PgValueFormat;\nuse std::num::Saturating;\n\n/// <https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-BIND>\n///\n/// ## Note:\n///\n/// The integer values for number of bind parameters, number of parameter format codes,\n/// and number of result format codes all are interpreted as *unsigned*!\n#[derive(Debug)]\npub struct Bind<'a> {\n    /// The ID of the destination portal (`PortalId::UNNAMED` selects the unnamed portal).\n    pub portal: PortalId,\n\n    /// The id of the source prepared statement.\n    pub statement: StatementId,\n\n    /// The parameter format codes. Each must presently be zero (text) or one (binary).\n    ///\n    /// There can be zero to indicate that there are no parameters or that the parameters all use the\n    /// default format (text); or one, in which case the specified format code is applied to all\n    /// parameters; or it can equal the actual number of parameters.\n    pub formats: &'a [PgValueFormat],\n\n    // Note: interpreted as unsigned, as is `formats.len()` and `result_formats.len()`\n    /// The number of parameters.\n    ///\n    /// May be different from `formats.len()`\n    pub num_params: u16,\n\n    /// The value of each parameter, in the indicated format.\n    pub params: &'a [u8],\n\n    /// The result-column format codes. Each must presently be zero (text) or one (binary).\n    ///\n    /// There can be zero to indicate that there are no result columns or that the\n    /// result columns should all use the default format (text); or one, in which\n    /// case the specified format code is applied to all result columns (if any);\n    /// or it can equal the actual number of result columns of the query.\n    pub result_formats: &'a [PgValueFormat],\n}\n\nimpl FrontendMessage for Bind<'_> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Bind;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        let mut size = Saturating(0);\n        size += self.portal.name_len();\n        size += self.statement.name_len();\n\n        // Parameter formats and length prefix\n        size += 2;\n        size += self.formats.len();\n\n        // `num_params`\n        size += 2;\n\n        size += self.params.len();\n\n        // Result formats and length prefix\n        size += 2;\n        size += self.result_formats.len();\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), crate::Error> {\n        buf.put_portal_name(self.portal);\n\n        buf.put_statement_name(self.statement);\n\n        // NOTE: the integer values for the number of parameters and format codes in this message\n        // are all interpreted as *unsigned*!\n        //\n        // https://github.com/launchbadge/sqlx/issues/3464\n        let formats_len = u16::try_from(self.formats.len()).map_err(|_| {\n            err_protocol!(\"too many parameter format codes ({})\", self.formats.len())\n        })?;\n\n        buf.extend(formats_len.to_be_bytes());\n\n        for &format in self.formats {\n            buf.extend((format as i16).to_be_bytes());\n        }\n\n        buf.extend(self.num_params.to_be_bytes());\n\n        buf.extend(self.params);\n\n        let result_formats_len = u16::try_from(self.formats.len())\n            .map_err(|_| err_protocol!(\"too many result format codes ({})\", self.formats.len()))?;\n\n        buf.extend(result_formats_len.to_be_bytes());\n\n        for &format in self.result_formats {\n            buf.extend((format as i16).to_be_bytes());\n        }\n\n        Ok(())\n    }\n}\n\n// TODO: Unit Test Bind\n// TODO: Benchmark Bind\n"
  },
  {
    "path": "sqlx-postgres/src/message/close.rs",
    "content": "use crate::io::{PgBufMutExt, PortalId, StatementId};\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse std::num::Saturating;\n\nconst CLOSE_PORTAL: u8 = b'P';\nconst CLOSE_STATEMENT: u8 = b'S';\n\n#[derive(Debug)]\n#[allow(dead_code)]\npub enum Close {\n    Statement(StatementId),\n    Portal(PortalId),\n}\n\nimpl FrontendMessage for Close {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Close;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        // Either `CLOSE_PORTAL` or `CLOSE_STATEMENT`\n        let mut size = Saturating(1);\n\n        match self {\n            Close::Statement(id) => size += id.name_len(),\n            Close::Portal(id) => size += id.name_len(),\n        }\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), crate::Error> {\n        match self {\n            Close::Statement(id) => {\n                buf.push(CLOSE_STATEMENT);\n                buf.put_statement_name(*id);\n            }\n\n            Close::Portal(id) => {\n                buf.push(CLOSE_PORTAL);\n                buf.put_portal_name(*id);\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/command_complete.rs",
    "content": "use atoi::atoi;\nuse memchr::memrchr;\nuse sqlx_core::bytes::Bytes;\n\nuse crate::error::Error;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n#[derive(Debug)]\npub struct CommandComplete {\n    /// The command tag. This is usually a single word that identifies which SQL command\n    /// was completed.\n    tag: Bytes,\n}\n\nimpl BackendMessage for CommandComplete {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::CommandComplete;\n\n    fn decode_body(bytes: Bytes) -> Result<Self, Error> {\n        Ok(CommandComplete { tag: bytes })\n    }\n}\n\nimpl CommandComplete {\n    /// Returns the number of rows affected.\n    /// If the command does not return rows (e.g., \"CREATE TABLE\"), returns 0.\n    pub fn rows_affected(&self) -> u64 {\n        // Look backwards for the first SPACE\n        memrchr(b' ', &self.tag)\n            // This is either a word or the number of rows affected\n            .and_then(|i| atoi(&self.tag[(i + 1)..]))\n            .unwrap_or(0)\n    }\n}\n\n#[test]\nfn test_decode_command_complete_for_insert() {\n    const DATA: &[u8] = b\"INSERT 0 1214\\0\";\n\n    let cc = CommandComplete::decode_body(Bytes::from_static(DATA)).unwrap();\n\n    assert_eq!(cc.rows_affected(), 1214);\n}\n\n#[test]\nfn test_decode_command_complete_for_begin() {\n    const DATA: &[u8] = b\"BEGIN\\0\";\n\n    let cc = CommandComplete::decode_body(Bytes::from_static(DATA)).unwrap();\n\n    assert_eq!(cc.rows_affected(), 0);\n}\n\n#[test]\nfn test_decode_command_complete_for_update() {\n    const DATA: &[u8] = b\"UPDATE 5\\0\";\n\n    let cc = CommandComplete::decode_body(Bytes::from_static(DATA)).unwrap();\n\n    assert_eq!(cc.rows_affected(), 5);\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_command_complete(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"INSERT 0 1214\\0\";\n\n    b.iter(|| {\n        let _ = CommandComplete::decode_body(test::black_box(Bytes::from_static(DATA)));\n    });\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_command_complete_rows_affected(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"INSERT 0 1214\\0\";\n\n    let data = CommandComplete::decode_body(Bytes::from_static(DATA)).unwrap();\n\n    b.iter(|| {\n        let _rows = test::black_box(&data).rows_affected();\n    });\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/copy.rs",
    "content": "use crate::error::Result;\nuse crate::io::BufMutExt;\nuse crate::message::{\n    BackendMessage, BackendMessageFormat, FrontendMessage, FrontendMessageFormat,\n};\nuse sqlx_core::bytes::{Buf, Bytes};\nuse sqlx_core::Error;\nuse std::num::Saturating;\nuse std::ops::Deref;\n\n/// The same structure is sent for both `CopyInResponse` and `CopyOutResponse`\npub struct CopyResponseData {\n    pub format: i8,\n    pub num_columns: i16,\n    pub format_codes: Vec<i16>,\n}\n\npub struct CopyInResponse(pub CopyResponseData);\n\n#[allow(dead_code)]\npub struct CopyOutResponse(pub CopyResponseData);\n\npub struct CopyData<B>(pub B);\n\npub struct CopyFail {\n    pub message: String,\n}\n\npub struct CopyDone;\n\nimpl CopyResponseData {\n    #[inline]\n    fn decode(mut buf: Bytes) -> Result<Self> {\n        let format = buf.get_i8();\n        let num_columns = buf.get_i16();\n\n        let format_codes = (0..num_columns).map(|_| buf.get_i16()).collect();\n\n        Ok(CopyResponseData {\n            format,\n            num_columns,\n            format_codes,\n        })\n    }\n}\n\nimpl BackendMessage for CopyInResponse {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::CopyInResponse;\n\n    #[inline(always)]\n    fn decode_body(buf: Bytes) -> std::result::Result<Self, Error> {\n        Ok(Self(CopyResponseData::decode(buf)?))\n    }\n}\n\nimpl BackendMessage for CopyOutResponse {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::CopyOutResponse;\n\n    #[inline(always)]\n    fn decode_body(buf: Bytes) -> std::result::Result<Self, Error> {\n        Ok(Self(CopyResponseData::decode(buf)?))\n    }\n}\n\nimpl BackendMessage for CopyData<Bytes> {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::CopyData;\n\n    #[inline(always)]\n    fn decode_body(buf: Bytes) -> std::result::Result<Self, Error> {\n        Ok(Self(buf))\n    }\n}\n\nimpl<B: Deref<Target = [u8]>> FrontendMessage for CopyData<B> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::CopyData;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(self.0.len())\n    }\n\n    #[inline(always)]\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        buf.extend_from_slice(&self.0);\n        Ok(())\n    }\n}\n\nimpl FrontendMessage for CopyFail {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::CopyFail;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(self.message.len())\n    }\n\n    #[inline(always)]\n    fn encode_body(&self, buf: &mut Vec<u8>) -> std::result::Result<(), Error> {\n        buf.put_str_nul(&self.message);\n        Ok(())\n    }\n}\n\nimpl CopyFail {\n    #[inline(always)]\n    pub fn new(msg: impl Into<String>) -> CopyFail {\n        CopyFail {\n            message: msg.into(),\n        }\n    }\n}\n\nimpl FrontendMessage for CopyDone {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::CopyDone;\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(0)\n    }\n\n    #[inline(always)]\n    fn encode_body(&self, _buf: &mut Vec<u8>) -> std::result::Result<(), Error> {\n        Ok(())\n    }\n}\n\nimpl BackendMessage for CopyDone {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::CopyDone;\n\n    #[inline(always)]\n    fn decode_body(bytes: Bytes) -> std::result::Result<Self, Error> {\n        if !bytes.is_empty() {\n            // Not fatal but may indicate a protocol change\n            tracing::debug!(\n                \"Postgres backend returned non-empty message for CopyDone: \\\"{}\\\"\",\n                bytes.escape_ascii()\n            )\n        }\n\n        Ok(CopyDone)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/data_row.rs",
    "content": "use byteorder::{BigEndian, ByteOrder};\nuse sqlx_core::bytes::Bytes;\nuse std::ops::Range;\n\nuse crate::error::Error;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n/// A row of data from the database.\n#[derive(Debug)]\npub struct DataRow {\n    pub(crate) storage: Bytes,\n\n    /// Ranges into the stored row data.\n    /// This uses `u32` instead of usize to reduce the size of this type. Values cannot be larger\n    /// than `i32` in postgres.\n    pub(crate) values: Vec<Option<Range<u32>>>,\n}\n\nimpl DataRow {\n    #[inline]\n    pub(crate) fn get(&self, index: usize) -> Option<&'_ [u8]> {\n        self.values[index]\n            .as_ref()\n            .map(|col| &self.storage[(col.start as usize)..(col.end as usize)])\n    }\n}\n\nimpl BackendMessage for DataRow {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::DataRow;\n\n    fn decode_body(buf: Bytes) -> Result<Self, Error> {\n        if buf.len() < 2 {\n            return Err(err_protocol!(\n                \"expected at least 2 bytes, got {}\",\n                buf.len()\n            ));\n        }\n\n        let cnt = BigEndian::read_u16(&buf) as usize;\n\n        let mut values = Vec::with_capacity(cnt);\n        let mut offset: u32 = 2;\n\n        for _ in 0..cnt {\n            let value_start = offset\n                .checked_add(4)\n                .ok_or_else(|| err_protocol!(\"next value start out of range (offset: {offset})\"))?;\n\n            // widen both to a larger type for a safe comparison\n            if (buf.len() as u64) < (value_start as u64) {\n                return Err(err_protocol!(\n                    \"expected 4 bytes at offset {offset}, got {}\",\n                    (value_start as u64) - (buf.len() as u64)\n                ));\n            }\n\n            // Length of the column value, in bytes (this count does not include itself).\n            // Can be zero. As a special case, -1 indicates a NULL column value.\n            // No value bytes follow in the NULL case.\n            //\n            // we know `offset` is within range of `buf.len()` from the above check\n            #[allow(clippy::cast_possible_truncation)]\n            let length = BigEndian::read_i32(&buf[(offset as usize)..]);\n\n            if let Ok(length) = u32::try_from(length) {\n                let value_end = value_start.checked_add(length).ok_or_else(|| {\n                    err_protocol!(\"value_start + length out of range ({offset} + {length})\")\n                })?;\n\n                values.push(Some(value_start..value_end));\n                offset = value_end;\n            } else {\n                // Negative values signify NULL\n                values.push(None);\n                // `value_start` is actually the next value now.\n                offset = value_start;\n            }\n        }\n\n        Ok(Self {\n            storage: buf,\n            values,\n        })\n    }\n}\n\n#[test]\nfn test_decode_data_row() {\n    const DATA: &[u8] = b\"\\\n        \\x00\\x08\\\n        \\xff\\xff\\xff\\xff\\\n        \\x00\\x00\\x00\\x04\\\n        \\x00\\x00\\x00\\n\\\n        \\xff\\xff\\xff\\xff\\\n        \\x00\\x00\\x00\\x04\\\n        \\x00\\x00\\x00\\x14\\\n        \\xff\\xff\\xff\\xff\\\n        \\x00\\x00\\x00\\x04\\\n        \\x00\\x00\\x00(\\\n        \\xff\\xff\\xff\\xff\\\n        \\x00\\x00\\x00\\x04\\\n        \\x00\\x00\\x00P\";\n\n    let row = DataRow::decode_body(DATA.into()).unwrap();\n\n    assert_eq!(row.values.len(), 8);\n\n    assert!(row.get(0).is_none());\n    assert_eq!(row.get(1).unwrap(), &[0_u8, 0, 0, 10][..]);\n    assert!(row.get(2).is_none());\n    assert_eq!(row.get(3).unwrap(), &[0_u8, 0, 0, 20][..]);\n    assert!(row.get(4).is_none());\n    assert_eq!(row.get(5).unwrap(), &[0_u8, 0, 0, 40][..]);\n    assert!(row.get(6).is_none());\n    assert_eq!(row.get(7).unwrap(), &[0_u8, 0, 0, 80][..]);\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_data_row_get(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"\\x00\\x08\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\n\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x14\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00(\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00P\";\n\n    let row = DataRow::decode_body(test::black_box(Bytes::from_static(DATA))).unwrap();\n\n    b.iter(|| {\n        let _value = test::black_box(&row).get(3);\n    });\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_data_row(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"\\x00\\x08\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\n\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00\\x14\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00(\\xff\\xff\\xff\\xff\\x00\\x00\\x00\\x04\\x00\\x00\\x00P\";\n\n    b.iter(|| {\n        let _ = DataRow::decode_body(test::black_box(Bytes::from_static(DATA)));\n    });\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/describe.rs",
    "content": "use crate::io::{PgBufMutExt, PortalId, StatementId};\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\nconst DESCRIBE_PORTAL: u8 = b'P';\nconst DESCRIBE_STATEMENT: u8 = b'S';\n\n/// Note: will emit both a RowDescription and a ParameterDescription message\n#[derive(Debug)]\n#[allow(dead_code)]\npub enum Describe {\n    Statement(StatementId),\n    Portal(PortalId),\n}\n\nimpl FrontendMessage for Describe {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Describe;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        // Either `DESCRIBE_PORTAL` or `DESCRIBE_STATEMENT`\n        let mut size = Saturating(1);\n\n        match self {\n            Describe::Statement(id) => size += id.name_len(),\n            Describe::Portal(id) => size += id.name_len(),\n        }\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        match self {\n            // #[likely]\n            Describe::Statement(id) => {\n                buf.push(DESCRIBE_STATEMENT);\n                buf.put_statement_name(*id);\n            }\n\n            Describe::Portal(id) => {\n                buf.push(DESCRIBE_PORTAL);\n                buf.put_portal_name(*id);\n            }\n        }\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::message::FrontendMessage;\n\n    use super::{Describe, PortalId, StatementId};\n\n    #[test]\n    fn test_encode_describe_portal() {\n        const EXPECTED: &[u8] = b\"D\\0\\0\\0\\x17Psqlx_p_1234567890\\0\";\n\n        let mut buf = Vec::new();\n        let m = Describe::Portal(PortalId::TEST_VAL);\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n\n    #[test]\n    fn test_encode_describe_unnamed_portal() {\n        const EXPECTED: &[u8] = b\"D\\0\\0\\0\\x06P\\0\";\n\n        let mut buf = Vec::new();\n        let m = Describe::Portal(PortalId::UNNAMED);\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n\n    #[test]\n    fn test_encode_describe_statement() {\n        const EXPECTED: &[u8] = b\"D\\0\\0\\0\\x17Ssqlx_s_1234567890\\0\";\n\n        let mut buf = Vec::new();\n        let m = Describe::Statement(StatementId::TEST_VAL);\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n\n    #[test]\n    fn test_encode_describe_unnamed_statement() {\n        const EXPECTED: &[u8] = b\"D\\0\\0\\0\\x06S\\0\";\n\n        let mut buf = Vec::new();\n        let m = Describe::Statement(StatementId::UNNAMED);\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/execute.rs",
    "content": "use std::num::Saturating;\n\nuse sqlx_core::Error;\n\nuse crate::io::{PgBufMutExt, PortalId};\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\n\npub struct Execute {\n    /// The id of the portal to execute.\n    pub portal: PortalId,\n\n    /// Maximum number of rows to return, if portal contains a query\n    /// that returns rows (ignored otherwise). Zero denotes “no limit”.\n    pub limit: u32,\n}\n\nimpl FrontendMessage for Execute {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Execute;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        let mut size = Saturating(0);\n\n        size += self.portal.name_len();\n        size += 2; // limit\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        buf.put_portal_name(self.portal);\n        buf.extend(&self.limit.to_be_bytes());\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::io::PortalId;\n    use crate::message::FrontendMessage;\n\n    use super::Execute;\n\n    #[test]\n    fn test_encode_execute_named_portal() {\n        const EXPECTED: &[u8] = b\"E\\0\\0\\0\\x1Asqlx_p_1234567890\\0\\0\\0\\0\\x02\";\n\n        let mut buf = Vec::new();\n        let m = Execute {\n            portal: PortalId::TEST_VAL,\n            limit: 2,\n        };\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n\n    #[test]\n    fn test_encode_execute_unnamed_portal() {\n        const EXPECTED: &[u8] = b\"E\\0\\0\\0\\x09\\0\\x49\\x96\\x02\\xD2\";\n\n        let mut buf = Vec::new();\n        let m = Execute {\n            portal: PortalId::UNNAMED,\n            limit: 1234567890,\n        };\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/flush.rs",
    "content": "use crate::message::{FrontendMessage, FrontendMessageFormat};\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\n/// The Flush message does not cause any specific output to be generated,\n/// but forces the backend to deliver any data pending in its output buffers.\n///\n/// A Flush must be sent after any extended-query command except Sync, if the\n/// frontend wishes to examine the results of that command before issuing more commands.\n#[derive(Debug)]\npub struct Flush;\n\nimpl FrontendMessage for Flush {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Flush;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(0)\n    }\n\n    #[inline(always)]\n    fn encode_body(&self, _buf: &mut Vec<u8>) -> Result<(), Error> {\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/mod.rs",
    "content": "use sqlx_core::bytes::Bytes;\nuse std::num::Saturating;\n\nuse crate::error::Error;\nuse crate::io::PgBufMutExt;\n\nmod authentication;\nmod backend_key_data;\nmod bind;\nmod close;\nmod command_complete;\nmod copy;\nmod data_row;\nmod describe;\nmod execute;\nmod flush;\nmod notification;\nmod parameter_description;\nmod parameter_status;\nmod parse;\nmod parse_complete;\nmod password;\nmod query;\nmod ready_for_query;\nmod response;\nmod row_description;\nmod sasl;\nmod ssl_request;\nmod startup;\nmod sync;\nmod terminate;\n\npub use authentication::{Authentication, AuthenticationSasl};\npub use backend_key_data::BackendKeyData;\npub use bind::Bind;\npub use close::Close;\npub use command_complete::CommandComplete;\npub use copy::{CopyData, CopyDone, CopyFail, CopyInResponse, CopyOutResponse, CopyResponseData};\npub use data_row::DataRow;\npub use describe::Describe;\npub use execute::Execute;\n#[allow(unused_imports)]\npub use flush::Flush;\npub use notification::Notification;\npub use parameter_description::ParameterDescription;\npub use parameter_status::ParameterStatus;\npub use parse::Parse;\npub use parse_complete::ParseComplete;\npub use password::Password;\npub use query::Query;\npub use ready_for_query::{ReadyForQuery, TransactionStatus};\npub use response::{Notice, PgSeverity};\npub use row_description::RowDescription;\npub use sasl::{SaslInitialResponse, SaslResponse};\nuse sqlx_core::io::ProtocolEncode;\npub use ssl_request::SslRequest;\npub use startup::Startup;\npub use sync::Sync;\npub use terminate::Terminate;\n\n// Note: we can't use the same enum for both frontend and backend message formats\n// because there are duplicated format codes between them.\n//\n// For example, `Close` (frontend) and `CommandComplete` (backend) both use format code `C`.\n// <https://www.postgresql.org/docs/current/protocol-message-formats.html>\n#[derive(Debug, PartialOrd, PartialEq)]\n#[repr(u8)]\npub enum FrontendMessageFormat {\n    Bind = b'B',\n    Close = b'C',\n    CopyData = b'd',\n    CopyDone = b'c',\n    CopyFail = b'f',\n    Describe = b'D',\n    Execute = b'E',\n    Flush = b'H',\n    Parse = b'P',\n    /// This message format is polymorphic. It's used for:\n    ///\n    /// * Plain password responses\n    /// * MD5 password responses\n    /// * SASL responses\n    /// * GSSAPI/SSPI responses\n    PasswordPolymorphic = b'p',\n    Query = b'Q',\n    Sync = b'S',\n    Terminate = b'X',\n}\n\n#[derive(Debug, PartialOrd, PartialEq)]\n#[repr(u8)]\npub enum BackendMessageFormat {\n    Authentication,\n    BackendKeyData,\n    BindComplete,\n    CloseComplete,\n    CommandComplete,\n    CopyData,\n    CopyDone,\n    CopyInResponse,\n    CopyOutResponse,\n    DataRow,\n    EmptyQueryResponse,\n    ErrorResponse,\n    NoData,\n    NoticeResponse,\n    NotificationResponse,\n    ParameterDescription,\n    ParameterStatus,\n    ParseComplete,\n    PortalSuspended,\n    ReadyForQuery,\n    RowDescription,\n}\n\n#[derive(Debug)]\npub struct ReceivedMessage {\n    pub format: BackendMessageFormat,\n    pub contents: Bytes,\n}\n\nimpl ReceivedMessage {\n    #[inline]\n    pub fn decode<T>(self) -> Result<T, Error>\n    where\n        T: BackendMessage,\n    {\n        if T::FORMAT != self.format {\n            return Err(err_protocol!(\n                \"Postgres protocol error: expected {:?}, got {:?}\",\n                T::FORMAT,\n                self.format\n            ));\n        }\n\n        T::decode_body(self.contents).map_err(|e| match e {\n            Error::Protocol(s) => {\n                err_protocol!(\"Postgres protocol error (reading {:?}): {s}\", self.format)\n            }\n            other => other,\n        })\n    }\n}\n\nimpl BackendMessageFormat {\n    pub fn try_from_u8(v: u8) -> Result<Self, Error> {\n        // https://www.postgresql.org/docs/current/protocol-message-formats.html\n\n        Ok(match v {\n            b'1' => BackendMessageFormat::ParseComplete,\n            b'2' => BackendMessageFormat::BindComplete,\n            b'3' => BackendMessageFormat::CloseComplete,\n            b'C' => BackendMessageFormat::CommandComplete,\n            b'd' => BackendMessageFormat::CopyData,\n            b'c' => BackendMessageFormat::CopyDone,\n            b'G' => BackendMessageFormat::CopyInResponse,\n            b'H' => BackendMessageFormat::CopyOutResponse,\n            b'D' => BackendMessageFormat::DataRow,\n            b'E' => BackendMessageFormat::ErrorResponse,\n            b'I' => BackendMessageFormat::EmptyQueryResponse,\n            b'A' => BackendMessageFormat::NotificationResponse,\n            b'K' => BackendMessageFormat::BackendKeyData,\n            b'N' => BackendMessageFormat::NoticeResponse,\n            b'R' => BackendMessageFormat::Authentication,\n            b'S' => BackendMessageFormat::ParameterStatus,\n            b'T' => BackendMessageFormat::RowDescription,\n            b'Z' => BackendMessageFormat::ReadyForQuery,\n            b'n' => BackendMessageFormat::NoData,\n            b's' => BackendMessageFormat::PortalSuspended,\n            b't' => BackendMessageFormat::ParameterDescription,\n\n            _ => return Err(err_protocol!(\"unknown message type: {:?}\", v as char)),\n        })\n    }\n}\n\npub(crate) trait FrontendMessage: Sized {\n    /// The format prefix of this message.\n    const FORMAT: FrontendMessageFormat;\n\n    /// Return the amount of space, in bytes, to reserve in the buffer passed to [`Self::encode_body()`].\n    fn body_size_hint(&self) -> Saturating<usize>;\n\n    /// Encode this type as a Frontend message in the Postgres protocol.\n    ///\n    /// The implementation should *not* include `Self::FORMAT` or the length prefix.\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error>;\n\n    #[inline(always)]\n    #[cfg_attr(not(test), allow(dead_code))]\n    fn encode_msg(self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        EncodeMessage(self).encode(buf)\n    }\n}\n\npub(crate) trait BackendMessage: Sized {\n    /// The expected message format.\n    ///\n    /// <https://www.postgresql.org/docs/current/protocol-message-formats.html>\n    const FORMAT: BackendMessageFormat;\n\n    /// Decode this type from a Backend message in the Postgres protocol.\n    ///\n    /// The format code and length prefix have already been read and are not at the start of `bytes`.\n    fn decode_body(buf: Bytes) -> Result<Self, Error>;\n}\n\npub struct EncodeMessage<F>(pub F);\n\nimpl<F: FrontendMessage> ProtocolEncode<'_, ()> for EncodeMessage<F> {\n    fn encode_with(&self, buf: &mut Vec<u8>, _context: ()) -> Result<(), Error> {\n        let mut size_hint = self.0.body_size_hint();\n        // plus format code and length prefix\n        size_hint += 5;\n\n        // don't panic if `size_hint` is ridiculous\n        buf.try_reserve(size_hint.0).map_err(|e| {\n            err_protocol!(\n                \"Postgres protocol: error allocating {} bytes for encoding message {:?}: {e}\",\n                size_hint.0,\n                F::FORMAT,\n            )\n        })?;\n\n        buf.push(F::FORMAT as u8);\n\n        buf.put_length_prefixed(|buf| self.0.encode_body(buf))\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/notification.rs",
    "content": "use sqlx_core::bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::BufExt;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n#[derive(Debug)]\npub struct Notification {\n    pub(crate) process_id: u32,\n    pub(crate) channel: Bytes,\n    pub(crate) payload: Bytes,\n}\n\nimpl BackendMessage for Notification {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::NotificationResponse;\n\n    fn decode_body(mut buf: Bytes) -> Result<Self, Error> {\n        let process_id = buf.get_u32();\n        let channel = buf.get_bytes_nul()?;\n        let payload = buf.get_bytes_nul()?;\n\n        Ok(Self {\n            process_id,\n            channel,\n            payload,\n        })\n    }\n}\n\n#[test]\nfn test_decode_notification_response() {\n    const NOTIFICATION_RESPONSE: &[u8] = b\"\\x34\\x20\\x10\\x02TEST-CHANNEL\\0THIS IS A TEST\\0\";\n\n    let message = Notification::decode_body(Bytes::from(NOTIFICATION_RESPONSE)).unwrap();\n\n    assert_eq!(message.process_id, 0x34201002);\n    assert_eq!(&*message.channel, &b\"TEST-CHANNEL\"[..]);\n    assert_eq!(&*message.payload, &b\"THIS IS A TEST\"[..]);\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/parameter_description.rs",
    "content": "use smallvec::SmallVec;\nuse sqlx_core::bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::message::{BackendMessage, BackendMessageFormat};\nuse crate::types::Oid;\n\n#[derive(Debug)]\npub struct ParameterDescription {\n    pub types: SmallVec<[Oid; 6]>,\n}\n\nimpl BackendMessage for ParameterDescription {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::ParameterDescription;\n\n    fn decode_body(mut buf: Bytes) -> Result<Self, Error> {\n        // Note: this is correct, max parameters is 65535, not 32767\n        // https://github.com/launchbadge/sqlx/issues/3464\n        let cnt = buf.get_u16();\n        let mut types = SmallVec::with_capacity(cnt as usize);\n\n        for _ in 0..cnt {\n            types.push(Oid(buf.get_u32()));\n        }\n\n        Ok(Self { types })\n    }\n}\n\n#[test]\nfn test_decode_parameter_description() {\n    const DATA: &[u8] = b\"\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x00\";\n\n    let m = ParameterDescription::decode_body(DATA.into()).unwrap();\n\n    assert_eq!(m.types.len(), 2);\n    assert_eq!(m.types[0], Oid(0x0000_0000));\n    assert_eq!(m.types[1], Oid(0x0000_0500));\n}\n\n#[test]\nfn test_decode_empty_parameter_description() {\n    const DATA: &[u8] = b\"\\x00\\x00\";\n\n    let m = ParameterDescription::decode_body(DATA.into()).unwrap();\n\n    assert!(m.types.is_empty());\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_parameter_description(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"\\x00\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x05\\x00\";\n\n    b.iter(|| {\n        ParameterDescription::decode_body(test::black_box(Bytes::from_static(DATA))).unwrap();\n    });\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/parameter_status.rs",
    "content": "use sqlx_core::bytes::Bytes;\n\nuse crate::error::Error;\nuse crate::io::BufExt;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n#[derive(Debug)]\npub struct ParameterStatus {\n    pub name: String,\n    pub value: String,\n}\n\nimpl BackendMessage for ParameterStatus {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::ParameterStatus;\n\n    fn decode_body(mut buf: Bytes) -> Result<Self, Error> {\n        let name = buf.get_str_nul()?;\n        let value = buf.get_str_nul()?;\n\n        Ok(Self { name, value })\n    }\n}\n\n#[test]\nfn test_decode_parameter_status() {\n    const DATA: &[u8] = b\"client_encoding\\x00UTF8\\x00\";\n\n    let m = ParameterStatus::decode_body(DATA.into()).unwrap();\n\n    assert_eq!(&m.name, \"client_encoding\");\n    assert_eq!(&m.value, \"UTF8\")\n}\n\n#[test]\nfn test_decode_empty_parameter_status() {\n    const DATA: &[u8] = b\"\\x00\\x00\";\n\n    let m = ParameterStatus::decode_body(DATA.into()).unwrap();\n\n    assert!(m.name.is_empty());\n    assert!(m.value.is_empty());\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_parameter_status(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"client_encoding\\x00UTF8\\x00\";\n\n    b.iter(|| {\n        ParameterStatus::decode_body(test::black_box(Bytes::from_static(DATA))).unwrap();\n    });\n}\n\n#[test]\nfn test_decode_parameter_status_response() {\n    const PARAMETER_STATUS_RESPONSE: &[u8] = b\"crdb_version\\0CockroachDB CCL v21.1.0 (x86_64-unknown-linux-gnu, built 2021/05/17 13:49:40, go1.15.11)\\0\";\n\n    let message = ParameterStatus::decode_body(Bytes::from(PARAMETER_STATUS_RESPONSE)).unwrap();\n\n    assert_eq!(message.name, \"crdb_version\");\n    assert_eq!(\n        message.value,\n        \"CockroachDB CCL v21.1.0 (x86_64-unknown-linux-gnu, built 2021/05/17 13:49:40, go1.15.11)\"\n    );\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/parse.rs",
    "content": "use crate::io::BufMutExt;\nuse crate::io::{PgBufMutExt, StatementId};\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse crate::types::Oid;\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\n#[derive(Debug)]\npub struct Parse<'a> {\n    /// The ID of the destination prepared statement.\n    pub statement: StatementId,\n\n    /// The query string to be parsed.\n    pub query: &'a str,\n\n    /// The parameter data types specified (could be zero). Note that this is not an\n    /// indication of the number of parameters that might appear in the query string,\n    /// only the number that the frontend wants to pre-specify types for.\n    pub param_types: &'a [Oid],\n}\n\nimpl FrontendMessage for Parse<'_> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Parse;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        let mut size = Saturating(0);\n\n        size += self.statement.name_len();\n\n        size += self.query.len();\n        size += 1; // NUL terminator\n\n        size += 2; // param_types_len\n\n        // `param_types`\n        size += self.param_types.len().saturating_mul(4);\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        buf.put_statement_name(self.statement);\n\n        buf.put_str_nul(self.query);\n\n        // Note: actually interpreted as unsigned\n        // https://github.com/launchbadge/sqlx/issues/3464\n        let param_types_len = u16::try_from(self.param_types.len()).map_err(|_| {\n            err_protocol!(\n                \"param_types.len() too large for binary protocol: {}\",\n                self.param_types.len()\n            )\n        })?;\n\n        buf.extend(param_types_len.to_be_bytes());\n\n        for &oid in self.param_types {\n            buf.extend(oid.0.to_be_bytes());\n        }\n\n        Ok(())\n    }\n}\n\n#[test]\nfn test_encode_parse() {\n    const EXPECTED: &[u8] = b\"P\\0\\0\\0\\x26sqlx_s_1234567890\\0SELECT $1\\0\\0\\x01\\0\\0\\0\\x19\";\n\n    let mut buf = Vec::new();\n    let m = Parse {\n        statement: StatementId::TEST_VAL,\n        query: \"SELECT $1\",\n        param_types: &[Oid(25)],\n    };\n\n    m.encode_msg(&mut buf).unwrap();\n\n    assert_eq!(buf, EXPECTED);\n}\n\n#[test]\nfn test_encode_parse_unnamed_statement() {\n    const EXPECTED: &[u8] = b\"P\\0\\0\\0\\x15\\0SELECT $1\\0\\0\\x01\\0\\0\\0\\x19\";\n\n    let mut buf = Vec::new();\n    let m = Parse {\n        statement: StatementId::UNNAMED,\n        query: \"SELECT $1\",\n        param_types: &[Oid(25)],\n    };\n\n    m.encode_msg(&mut buf).unwrap();\n\n    assert_eq!(buf, EXPECTED);\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/parse_complete.rs",
    "content": "use crate::message::{BackendMessage, BackendMessageFormat};\nuse sqlx_core::bytes::Bytes;\nuse sqlx_core::Error;\n\npub struct ParseComplete;\n\nimpl BackendMessage for ParseComplete {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::ParseComplete;\n\n    fn decode_body(_bytes: Bytes) -> Result<Self, Error> {\n        Ok(ParseComplete)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/password.rs",
    "content": "use crate::io::BufMutExt;\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse md5::{Digest, Md5};\nuse sqlx_core::Error;\nuse std::fmt::Write;\nuse std::num::Saturating;\n\n#[derive(Debug)]\npub enum Password<'a> {\n    Cleartext(&'a str),\n\n    Md5 {\n        password: &'a str,\n        username: &'a str,\n        salt: [u8; 4],\n    },\n}\n\nimpl FrontendMessage for Password<'_> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::PasswordPolymorphic;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        let mut size = Saturating(0);\n\n        match self {\n            Password::Cleartext(password) => {\n                // To avoid reporting the exact password length anywhere,\n                // we deliberately give a bad estimate.\n                //\n                // This shouldn't affect performance in the long run.\n                size += password\n                    .len()\n                    .saturating_add(1) // NUL terminator\n                    .checked_next_power_of_two()\n                    .unwrap_or(usize::MAX);\n            }\n            Password::Md5 { .. } => {\n                // \"md5<32 hex chars>\\0\"\n                size += 36;\n            }\n        }\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        match self {\n            Password::Cleartext(password) => {\n                buf.put_str_nul(password);\n            }\n\n            Password::Md5 {\n                username,\n                password,\n                salt,\n            } => {\n                // The actual `PasswordMessage` can be computed in SQL as\n                // `concat('md5', md5(concat(md5(concat(password, username)), random-salt)))`.\n\n                // Keep in mind the md5() function returns its result as a hex string.\n\n                let mut hasher = Md5::new();\n\n                hasher.update(password);\n                hasher.update(username);\n\n                let mut output = String::with_capacity(35);\n\n                let _ = write!(output, \"{:x}\", hasher.finalize_reset());\n\n                hasher.update(&output);\n                hasher.update(salt);\n\n                output.clear();\n\n                let _ = write!(output, \"md5{:x}\", hasher.finalize());\n\n                buf.put_str_nul(&output);\n            }\n        }\n\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use crate::message::FrontendMessage;\n\n    use super::Password;\n\n    #[test]\n    fn test_encode_clear_password() {\n        const EXPECTED: &[u8] = b\"p\\0\\0\\0\\rpassword\\0\";\n\n        let mut buf = Vec::new();\n        let m = Password::Cleartext(\"password\");\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n\n    #[test]\n    fn test_encode_md5_password() {\n        const EXPECTED: &[u8] = b\"p\\0\\0\\0(md53e2c9d99d49b201ef867a36f3f9ed62c\\0\";\n\n        let mut buf = Vec::new();\n        let m = Password::Md5 {\n            password: \"password\",\n            username: \"root\",\n            salt: [147, 24, 57, 152],\n        };\n\n        m.encode_msg(&mut buf).unwrap();\n\n        assert_eq!(buf, EXPECTED);\n    }\n\n    #[cfg(all(test, not(debug_assertions)))]\n    #[bench]\n    fn bench_encode_clear_password(b: &mut test::Bencher) {\n        use test::black_box;\n\n        let mut buf = Vec::with_capacity(128);\n\n        b.iter(|| {\n            buf.clear();\n\n            black_box(Password::Cleartext(\"password\")).encode_msg(&mut buf);\n        });\n    }\n\n    #[cfg(all(test, not(debug_assertions)))]\n    #[bench]\n    fn bench_encode_md5_password(b: &mut test::Bencher) {\n        use test::black_box;\n\n        let mut buf = Vec::with_capacity(128);\n\n        b.iter(|| {\n            buf.clear();\n\n            black_box(Password::Md5 {\n                password: \"password\",\n                username: \"root\",\n                salt: [147, 24, 57, 152],\n            })\n            .encode_msg(&mut buf);\n        });\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/query.rs",
    "content": "use crate::io::BufMutExt;\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\n#[derive(Debug)]\npub struct Query<'a>(pub &'a str);\n\nimpl FrontendMessage for Query<'_> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Query;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        let mut size = Saturating(0);\n\n        size += self.0.len();\n        size += 1; // NUL terminator\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        buf.put_str_nul(self.0);\n        Ok(())\n    }\n}\n\n#[test]\nfn test_encode_query() {\n    const EXPECTED: &[u8] = b\"Q\\0\\0\\0\\x0DSELECT 1\\0\";\n\n    let mut buf = Vec::new();\n    let m = Query(\"SELECT 1\");\n\n    m.encode_msg(&mut buf).unwrap();\n\n    assert_eq!(buf, EXPECTED);\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/ready_for_query.rs",
    "content": "use sqlx_core::bytes::Bytes;\n\nuse crate::error::Error;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n#[derive(Debug)]\n#[repr(u8)]\npub enum TransactionStatus {\n    /// Not in a transaction block.\n    Idle = b'I',\n\n    /// In a transaction block.\n    Transaction = b'T',\n\n    /// In a _failed_ transaction block. Queries will be rejected until block is ended.\n    Error = b'E',\n}\n\n#[derive(Debug)]\npub struct ReadyForQuery {\n    pub transaction_status: TransactionStatus,\n}\n\nimpl BackendMessage for ReadyForQuery {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::ReadyForQuery;\n\n    fn decode_body(buf: Bytes) -> Result<Self, Error> {\n        let status = match buf[0] {\n            b'I' => TransactionStatus::Idle,\n            b'T' => TransactionStatus::Transaction,\n            b'E' => TransactionStatus::Error,\n\n            status => {\n                return Err(err_protocol!(\n                    \"unknown transaction status: {:?}\",\n                    status as char\n                ));\n            }\n        };\n\n        Ok(Self {\n            transaction_status: status,\n        })\n    }\n}\n\n#[test]\nfn test_decode_ready_for_query() -> Result<(), Error> {\n    const DATA: &[u8] = b\"E\";\n\n    let m = ReadyForQuery::decode_body(Bytes::from_static(DATA))?;\n\n    assert!(matches!(m.transaction_status, TransactionStatus::Error));\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/response.rs",
    "content": "use std::ops::Range;\nuse std::str::from_utf8;\n\nuse memchr::memchr;\n\nuse sqlx_core::bytes::Bytes;\n\nuse crate::error::Error;\nuse crate::io::ProtocolDecode;\nuse crate::message::{BackendMessage, BackendMessageFormat};\n\n#[derive(Debug, Copy, Clone, Eq, PartialEq)]\n#[repr(u8)]\npub enum PgSeverity {\n    Panic,\n    Fatal,\n    Error,\n    Warning,\n    Notice,\n    Debug,\n    Info,\n    Log,\n}\n\nimpl PgSeverity {\n    #[inline]\n    pub fn is_error(self) -> bool {\n        matches!(self, Self::Panic | Self::Fatal | Self::Error)\n    }\n}\n\nimpl TryFrom<&str> for PgSeverity {\n    type Error = Error;\n\n    fn try_from(s: &str) -> Result<PgSeverity, Error> {\n        let result = match s {\n            \"PANIC\" => PgSeverity::Panic,\n            \"FATAL\" => PgSeverity::Fatal,\n            \"ERROR\" => PgSeverity::Error,\n            \"WARNING\" => PgSeverity::Warning,\n            \"NOTICE\" => PgSeverity::Notice,\n            \"DEBUG\" => PgSeverity::Debug,\n            \"INFO\" => PgSeverity::Info,\n            \"LOG\" => PgSeverity::Log,\n\n            severity => {\n                return Err(err_protocol!(\"unknown severity: {:?}\", severity));\n            }\n        };\n\n        Ok(result)\n    }\n}\n\n#[derive(Debug)]\npub struct Notice {\n    storage: Bytes,\n    severity: PgSeverity,\n    message: Range<usize>,\n    code: Range<usize>,\n}\n\nimpl Notice {\n    #[inline]\n    pub fn severity(&self) -> PgSeverity {\n        self.severity\n    }\n\n    #[inline]\n    pub fn code(&self) -> &str {\n        self.get_cached_str(self.code.clone())\n    }\n\n    #[inline]\n    pub fn message(&self) -> &str {\n        self.get_cached_str(self.message.clone())\n    }\n\n    // Field descriptions available here:\n    //  https://www.postgresql.org/docs/current/protocol-error-fields.html\n\n    #[inline]\n    pub fn get(&self, ty: u8) -> Option<&str> {\n        self.get_raw(ty).and_then(|v| from_utf8(v).ok())\n    }\n\n    pub fn get_raw(&self, ty: u8) -> Option<&[u8]> {\n        self.fields()\n            .filter(|(field, _)| *field == ty)\n            .map(|(_, range)| &self.storage[range])\n            .next()\n    }\n}\n\nimpl Notice {\n    #[inline]\n    fn fields(&self) -> Fields<'_> {\n        Fields {\n            storage: &self.storage,\n            offset: 0,\n        }\n    }\n\n    #[inline]\n    fn get_cached_str(&self, cache: Range<usize>) -> &str {\n        // unwrap: this cannot fail at this stage\n        from_utf8(&self.storage[cache]).unwrap()\n    }\n}\n\nimpl ProtocolDecode<'_> for Notice {\n    fn decode_with(buf: Bytes, _: ()) -> Result<Self, Error> {\n        // In order to support PostgreSQL 9.5 and older we need to parse the localized S field.\n        // Newer versions additionally come with the V field that is guaranteed to be in English.\n        // We thus read both versions and prefer the unlocalized one if available.\n        const DEFAULT_SEVERITY: PgSeverity = PgSeverity::Log;\n        let mut severity_v = None;\n        let mut severity_s = None;\n        let mut message = 0..0;\n        let mut code = 0..0;\n\n        // we cache the three always present fields\n        // this enables to keep the access time down for the fields most likely accessed\n\n        let fields = Fields {\n            storage: &buf,\n            offset: 0,\n        };\n\n        for (field, v) in fields {\n            if !(message.is_empty() || code.is_empty()) {\n                // stop iterating when we have the 3 fields we were looking for\n                // we assume V (severity) was the first field as it should be\n                break;\n            }\n\n            match field {\n                b'S' => {\n                    severity_s = from_utf8(&buf[v.clone()])\n                        // If the error string is not UTF-8, we have no hope of interpreting it,\n                        // localized or not. The `V` field would likely fail to parse as well.\n                        .map_err(|_| notice_protocol_err())?\n                        .try_into()\n                        // If we couldn't parse the severity here, it might just be localized.\n                        .ok();\n                }\n\n                b'V' => {\n                    // Propagate errors here, because V is not localized and\n                    // thus we are missing a possible variant.\n                    severity_v = Some(\n                        from_utf8(&buf[v.clone()])\n                            .map_err(|_| notice_protocol_err())?\n                            .try_into()?,\n                    );\n                }\n\n                b'M' => {\n                    _ = from_utf8(&buf[v.clone()]).map_err(|_| notice_protocol_err())?;\n                    message = v;\n                }\n\n                b'C' => {\n                    _ = from_utf8(&buf[v.clone()]).map_err(|_| notice_protocol_err())?;\n                    code = v;\n                }\n\n                // If more fields are added, make sure to check that they are valid UTF-8,\n                // otherwise the get_cached_str method will panic.\n                _ => {}\n            }\n        }\n\n        Ok(Self {\n            severity: severity_v.or(severity_s).unwrap_or(DEFAULT_SEVERITY),\n            message,\n            code,\n            storage: buf,\n        })\n    }\n}\n\nimpl BackendMessage for Notice {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::NoticeResponse;\n\n    fn decode_body(buf: Bytes) -> Result<Self, Error> {\n        // Keeping both impls for now\n        Self::decode_with(buf, ())\n    }\n}\n\n/// An iterator over each field in the Error (or Notice) response.\nstruct Fields<'a> {\n    storage: &'a [u8],\n    offset: usize,\n}\n\nimpl Iterator for Fields<'_> {\n    type Item = (u8, Range<usize>);\n\n    fn next(&mut self) -> Option<Self::Item> {\n        // The fields in the response body are sequentially stored as [tag][string],\n        // ending in a final, additional [nul]\n\n        let ty = *self.storage.get(self.offset)?;\n\n        if ty == 0 {\n            return None;\n        }\n\n        // Consume the type byte\n        self.offset = self.offset.checked_add(1)?;\n\n        let start = self.offset;\n\n        let len = memchr(b'\\0', self.storage.get(start..)?)?;\n\n        // Neither can overflow as they will always be `<= self.storage.len()`.\n        let end = self.offset + len;\n        self.offset = end + 1;\n\n        Some((ty, start..end))\n    }\n}\n\nfn notice_protocol_err() -> Error {\n    // https://github.com/launchbadge/sqlx/issues/1144\n    Error::Protocol(\n        \"Postgres returned a non-UTF-8 string for its error message. \\\n         This is most likely due to an error that occurred during authentication and \\\n         the default lc_messages locale is not binary-compatible with UTF-8. \\\n         See the server logs for the error details.\"\n            .into(),\n    )\n}\n\n#[test]\nfn test_decode_error_response() {\n    const DATA: &[u8] = b\"SNOTICE\\0VNOTICE\\0C42710\\0Mextension \\\"uuid-ossp\\\" already exists, skipping\\0Fextension.c\\0L1656\\0RCreateExtension\\0\\0\";\n\n    let m = Notice::decode(Bytes::from_static(DATA)).unwrap();\n\n    assert_eq!(\n        m.message(),\n        \"extension \\\"uuid-ossp\\\" already exists, skipping\"\n    );\n\n    assert!(matches!(m.severity(), PgSeverity::Notice));\n    assert_eq!(m.code(), \"42710\");\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_error_response_get_message(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"SNOTICE\\0VNOTICE\\0C42710\\0Mextension \\\"uuid-ossp\\\" already exists, skipping\\0Fextension.c\\0L1656\\0RCreateExtension\\0\\0\";\n\n    let res = Notice::decode(test::black_box(Bytes::from_static(DATA))).unwrap();\n\n    b.iter(|| {\n        let _ = test::black_box(&res).message();\n    });\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_decode_error_response(b: &mut test::Bencher) {\n    const DATA: &[u8] = b\"SNOTICE\\0VNOTICE\\0C42710\\0Mextension \\\"uuid-ossp\\\" already exists, skipping\\0Fextension.c\\0L1656\\0RCreateExtension\\0\\0\";\n\n    b.iter(|| {\n        let _ = Notice::decode(test::black_box(Bytes::from_static(DATA)));\n    });\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/row_description.rs",
    "content": "use sqlx_core::bytes::{Buf, Bytes};\n\nuse crate::error::Error;\nuse crate::io::BufExt;\nuse crate::message::{BackendMessage, BackendMessageFormat};\nuse crate::types::Oid;\n\n#[derive(Debug)]\npub struct RowDescription {\n    pub fields: Vec<Field>,\n}\n\n#[derive(Debug)]\npub struct Field {\n    /// The name of the field.\n    pub name: String,\n\n    /// If the field can be identified as a column of a specific table, the\n    /// object ID of the table; otherwise zero.\n    pub relation_id: Option<Oid>,\n\n    /// If the field can be identified as a column of a specific table, the attribute number of\n    /// the column; otherwise zero.\n    pub relation_attribute_no: Option<i16>,\n\n    /// The object ID of the field's data type.\n    pub data_type_id: Oid,\n\n    /// The data type size (see pg_type.typlen). Note that negative values denote\n    /// variable-width types.\n    #[allow(dead_code)]\n    pub data_type_size: i16,\n\n    /// The type modifier (see pg_attribute.atttypmod). The meaning of the\n    /// modifier is type-specific.\n    #[allow(dead_code)]\n    pub type_modifier: i32,\n\n    /// The format code being used for the field.\n    #[allow(dead_code)]\n    pub format: i16,\n}\n\nimpl BackendMessage for RowDescription {\n    const FORMAT: BackendMessageFormat = BackendMessageFormat::RowDescription;\n\n    fn decode_body(mut buf: Bytes) -> Result<Self, Error> {\n        if buf.len() < 2 {\n            return Err(err_protocol!(\n                \"expected at least 2 bytes, got {}\",\n                buf.len()\n            ));\n        }\n\n        let cnt = buf.get_u16();\n        let mut fields = Vec::with_capacity(cnt as usize);\n\n        for _ in 0..cnt {\n            let name = buf.get_str_nul()?.to_owned();\n\n            if buf.len() < 18 {\n                return Err(err_protocol!(\n                    \"expected at least 18 bytes after field name {name:?}, got {}\",\n                    buf.len()\n                ));\n            }\n\n            let relation_id = buf.get_u32();\n            let relation_attribute_no = buf.get_i16();\n            let data_type_id = Oid(buf.get_u32());\n            let data_type_size = buf.get_i16();\n            let type_modifier = buf.get_i32();\n            let format = buf.get_i16();\n\n            fields.push(Field {\n                name,\n                relation_id: if relation_id == 0 {\n                    None\n                } else {\n                    Some(Oid(relation_id))\n                },\n                relation_attribute_no: if relation_attribute_no == 0 {\n                    None\n                } else {\n                    Some(relation_attribute_no)\n                },\n                data_type_id,\n                data_type_size,\n                type_modifier,\n                format,\n            })\n        }\n\n        Ok(Self { fields })\n    }\n}\n\n// TODO: Unit Test RowDescription\n// TODO: Benchmark RowDescription\n"
  },
  {
    "path": "sqlx-postgres/src/message/sasl.rs",
    "content": "use crate::io::BufMutExt;\nuse crate::message::{FrontendMessage, FrontendMessageFormat};\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\npub struct SaslInitialResponse<'a> {\n    pub response: &'a str,\n    pub plus: bool,\n}\n\nimpl SaslInitialResponse<'_> {\n    #[inline(always)]\n    fn selected_mechanism(&self) -> &'static str {\n        if self.plus {\n            \"SCRAM-SHA-256-PLUS\"\n        } else {\n            \"SCRAM-SHA-256\"\n        }\n    }\n}\n\nimpl FrontendMessage for SaslInitialResponse<'_> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::PasswordPolymorphic;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        let mut size = Saturating(0);\n\n        size += self.selected_mechanism().len();\n        size += 1; // NUL terminator\n\n        size += 4; // response_len\n        size += self.response.len();\n\n        size\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        // name of the SASL authentication mechanism that the client selected\n        buf.put_str_nul(self.selected_mechanism());\n\n        let response_len = i32::try_from(self.response.len()).map_err(|_| {\n            err_protocol!(\n                \"SASL Initial Response length too long for protocol: {}\",\n                self.response.len()\n            )\n        })?;\n\n        buf.extend_from_slice(&response_len.to_be_bytes());\n        buf.extend_from_slice(self.response.as_bytes());\n\n        Ok(())\n    }\n}\n\npub struct SaslResponse<'a>(pub &'a str);\n\nimpl FrontendMessage for SaslResponse<'_> {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::PasswordPolymorphic;\n\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(self.0.len())\n    }\n\n    fn encode_body(&self, buf: &mut Vec<u8>) -> Result<(), Error> {\n        buf.extend(self.0.as_bytes());\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/ssl_request.rs",
    "content": "use crate::io::ProtocolEncode;\n\npub struct SslRequest;\n\nimpl SslRequest {\n    // https://www.postgresql.org/docs/current/protocol-message-formats.html#PROTOCOL-MESSAGE-FORMATS-SSLREQUEST\n    pub const BYTES: &'static [u8] = b\"\\x00\\x00\\x00\\x08\\x04\\xd2\\x16\\x2f\";\n}\n\n// Cannot impl FrontendMessage because it does not have a format code\nimpl ProtocolEncode<'_> for SslRequest {\n    #[inline(always)]\n    fn encode_with(&self, buf: &mut Vec<u8>, _context: ()) -> Result<(), crate::Error> {\n        buf.extend_from_slice(Self::BYTES);\n        Ok(())\n    }\n}\n\n#[test]\nfn test_encode_ssl_request() {\n    let mut buf = Vec::new();\n\n    // Int32(8)\n    // Length of message contents in bytes, including self.\n    buf.extend_from_slice(&8_u32.to_be_bytes());\n\n    // Int32(80877103)\n    // The SSL request code. The value is chosen to contain 1234 in the most significant 16 bits,\n    // and 5679 in the least significant 16 bits.\n    // (To avoid confusion, this code must not be the same as any protocol version number.)\n    buf.extend_from_slice(&(((1234 << 16) | 5679) as u32).to_be_bytes());\n\n    let mut encoded = Vec::new();\n    SslRequest.encode(&mut encoded).unwrap();\n\n    assert_eq!(buf, SslRequest::BYTES);\n    assert_eq!(buf, encoded);\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/startup.rs",
    "content": "use crate::io::PgBufMutExt;\nuse crate::io::{BufMutExt, ProtocolEncode};\n\n// To begin a session, a frontend opens a connection to the server and sends a startup message.\n// This message includes the names of the user and of the database the user wants to connect to;\n// it also identifies the particular protocol version to be used.\n\n// Optionally, the startup message can include additional settings for run-time parameters.\n\npub struct Startup<'a> {\n    /// The database user name to connect as. Required; there is no default.\n    pub username: Option<&'a str>,\n\n    /// The database to connect to. Defaults to the user name.\n    pub database: Option<&'a str>,\n\n    /// Additional start-up params.\n    /// <https://www.postgresql.org/docs/devel/runtime-config-client.html>\n    pub params: &'a [(&'a str, &'a str)],\n}\n\n// Startup cannot impl FrontendMessage because it doesn't have a format code.\nimpl ProtocolEncode<'_> for Startup<'_> {\n    fn encode_with(&self, buf: &mut Vec<u8>, _context: ()) -> Result<(), crate::Error> {\n        buf.reserve(120);\n\n        buf.put_length_prefixed(|buf| {\n            // The protocol version number. The most significant 16 bits are the\n            // major version number (3 for the protocol described here). The least\n            // significant 16 bits are the minor version number (0\n            // for the protocol described here)\n            buf.extend(&196_608_i32.to_be_bytes());\n\n            if let Some(username) = self.username {\n                // The database user name to connect as.\n                encode_startup_param(buf, \"user\", username);\n            }\n\n            if let Some(database) = self.database {\n                // The database to connect to. Defaults to the user name.\n                encode_startup_param(buf, \"database\", database);\n            }\n\n            for (name, value) in self.params {\n                encode_startup_param(buf, name, value);\n            }\n\n            // A zero byte is required as a terminator\n            // after the last name/value pair.\n            buf.push(0);\n\n            Ok(())\n        })\n    }\n}\n\n#[inline]\nfn encode_startup_param(buf: &mut Vec<u8>, name: &str, value: &str) {\n    buf.put_str_nul(name);\n    buf.put_str_nul(value);\n}\n\n#[test]\nfn test_encode_startup() {\n    const EXPECTED: &[u8] = b\"\\0\\0\\0)\\0\\x03\\0\\0user\\0postgres\\0database\\0postgres\\0\\0\";\n\n    let mut buf = Vec::new();\n    let m = Startup {\n        username: Some(\"postgres\"),\n        database: Some(\"postgres\"),\n        params: &[],\n    };\n\n    m.encode(&mut buf).unwrap();\n\n    assert_eq!(buf, EXPECTED);\n}\n\n#[cfg(all(test, not(debug_assertions)))]\n#[bench]\nfn bench_encode_startup(b: &mut test::Bencher) {\n    use test::black_box;\n\n    let mut buf = Vec::with_capacity(128);\n\n    b.iter(|| {\n        buf.clear();\n\n        black_box(Startup {\n            username: Some(\"postgres\"),\n            database: Some(\"postgres\"),\n            params: &[],\n        })\n        .encode(&mut buf);\n    });\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/sync.rs",
    "content": "use crate::message::{FrontendMessage, FrontendMessageFormat};\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\n#[derive(Debug)]\npub struct Sync;\n\nimpl FrontendMessage for Sync {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Sync;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(0)\n    }\n\n    #[inline(always)]\n    fn encode_body(&self, _buf: &mut Vec<u8>) -> Result<(), Error> {\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/message/terminate.rs",
    "content": "use crate::message::{FrontendMessage, FrontendMessageFormat};\nuse sqlx_core::Error;\nuse std::num::Saturating;\n\npub struct Terminate;\n\nimpl FrontendMessage for Terminate {\n    const FORMAT: FrontendMessageFormat = FrontendMessageFormat::Terminate;\n\n    #[inline(always)]\n    fn body_size_hint(&self) -> Saturating<usize> {\n        Saturating(0)\n    }\n\n    #[inline(always)]\n    fn encode_body(&self, _buf: &mut Vec<u8>) -> Result<(), Error> {\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/migrate.rs",
    "content": "use std::str::FromStr;\nuse std::time::Duration;\nuse std::time::Instant;\n\nuse futures_core::future::BoxFuture;\n\npub(crate) use sqlx_core::migrate::MigrateError;\npub(crate) use sqlx_core::migrate::{AppliedMigration, Migration};\npub(crate) use sqlx_core::migrate::{Migrate, MigrateDatabase};\nuse sqlx_core::sql_str::AssertSqlSafe;\n\nuse crate::connection::{ConnectOptions, Connection};\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::query::query;\nuse crate::query_as::query_as;\nuse crate::query_scalar::query_scalar;\nuse crate::{PgConnectOptions, PgConnection, Postgres};\n\nfn parse_for_maintenance(url: &str) -> Result<(PgConnectOptions, String), Error> {\n    let mut options = PgConnectOptions::from_str(url)?;\n\n    // pull out the name of the database to create\n    let database = options\n        .database\n        .as_deref()\n        .unwrap_or(&options.username)\n        .to_owned();\n\n    // switch us to the maintenance database\n    // use `postgres` _unless_ the database is postgres, in which case, use `template1`\n    // this matches the behavior of the `createdb` util\n    options.database = if database == \"postgres\" {\n        Some(\"template1\".into())\n    } else {\n        Some(\"postgres\".into())\n    };\n\n    Ok((options, database))\n}\n\nimpl MigrateDatabase for Postgres {\n    async fn create_database(url: &str) -> Result<(), Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let _ = conn\n            .execute(AssertSqlSafe(format!(\n                \"CREATE DATABASE \\\"{}\\\"\",\n                database.replace('\"', \"\\\"\\\"\")\n            )))\n            .await?;\n\n        Ok(())\n    }\n\n    async fn database_exists(url: &str) -> Result<bool, Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let exists: bool =\n            query_scalar(\"select exists(SELECT 1 from pg_database WHERE datname = $1)\")\n                .bind(database)\n                .fetch_one(&mut conn)\n                .await?;\n\n        Ok(exists)\n    }\n\n    async fn drop_database(url: &str) -> Result<(), Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let _ = conn\n            .execute(AssertSqlSafe(format!(\n                \"DROP DATABASE IF EXISTS \\\"{}\\\"\",\n                database.replace('\"', \"\\\"\\\"\")\n            )))\n            .await?;\n\n        Ok(())\n    }\n\n    async fn force_drop_database(url: &str) -> Result<(), Error> {\n        let (options, database) = parse_for_maintenance(url)?;\n        let mut conn = options.connect().await?;\n\n        let row: (String,) = query_as(\"SELECT current_setting('server_version_num')\")\n            .fetch_one(&mut conn)\n            .await?;\n\n        let version = row.0.parse::<i32>().unwrap();\n\n        let pid_type = if version >= 90200 { \"pid\" } else { \"procpid\" };\n\n        conn.execute(AssertSqlSafe(format!(\n            \"SELECT pg_terminate_backend(pg_stat_activity.{pid_type}) FROM pg_stat_activity \\\n                 WHERE pg_stat_activity.datname = '{database}' AND {pid_type} <> pg_backend_pid()\"\n        )))\n        .await?;\n\n        Self::drop_database(url).await\n    }\n}\n\nimpl Migrate for PgConnection {\n    fn create_schema_if_not_exists<'e>(\n        &'e mut self,\n        schema_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            self.execute(AssertSqlSafe(format!(\n                r#\"CREATE SCHEMA IF NOT EXISTS {schema_name};\"#\n            )))\n            .await?;\n\n            Ok(())\n        })\n    }\n\n    fn ensure_migrations_table<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            self.execute(AssertSqlSafe(format!(\n                r#\"\nCREATE TABLE IF NOT EXISTS {table_name} (\n    version BIGINT PRIMARY KEY,\n    description TEXT NOT NULL,\n    installed_on TIMESTAMPTZ NOT NULL DEFAULT now(),\n    success BOOLEAN NOT NULL,\n    checksum BYTEA NOT NULL,\n    execution_time BIGINT NOT NULL\n);\n                \"#\n            )))\n            .await?;\n\n            Ok(())\n        })\n    }\n\n    fn dirty_version<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Option<i64>, MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            let row: Option<(i64,)> = query_as(AssertSqlSafe(format!(\n                \"SELECT version FROM {table_name} WHERE success = false ORDER BY version LIMIT 1\"\n            )))\n            .fetch_optional(self)\n            .await?;\n\n            Ok(row.map(|r| r.0))\n        })\n    }\n\n    fn list_applied_migrations<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>> {\n        Box::pin(async move {\n            // language=SQL\n            let rows: Vec<(i64, Vec<u8>)> = query_as(AssertSqlSafe(format!(\n                \"SELECT version, checksum FROM {table_name} ORDER BY version\"\n            )))\n            .fetch_all(self)\n            .await?;\n\n            let migrations = rows\n                .into_iter()\n                .map(|(version, checksum)| AppliedMigration {\n                    version,\n                    checksum: checksum.into(),\n                })\n                .collect();\n\n            Ok(migrations)\n        })\n    }\n\n    fn lock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async move {\n            let database_name = current_database(self).await?;\n            let lock_id = generate_lock_id(&database_name);\n\n            // create an application lock over the database\n            // this function will not return until the lock is acquired\n\n            // https://www.postgresql.org/docs/current/explicit-locking.html#ADVISORY-LOCKS\n            // https://www.postgresql.org/docs/current/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS-TABLE\n\n            // language=SQL\n            let _ = query(\"SELECT pg_advisory_lock($1)\")\n                .bind(lock_id)\n                .execute(self)\n                .await?;\n\n            Ok(())\n        })\n    }\n\n    fn unlock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async move {\n            let database_name = current_database(self).await?;\n            let lock_id = generate_lock_id(&database_name);\n\n            // language=SQL\n            let _ = query(\"SELECT pg_advisory_unlock($1)\")\n                .bind(lock_id)\n                .execute(self)\n                .await?;\n\n            Ok(())\n        })\n    }\n\n    fn apply<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async move {\n            let start = Instant::now();\n\n            // execute migration queries\n            if migration.no_tx {\n                execute_migration(self, table_name, migration).await?;\n            } else {\n                // Use a single transaction for the actual migration script and the essential bookkeeping so we never\n                // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.\n                // The `execution_time` however can only be measured for the whole transaction. This value _only_ exists for\n                // data lineage and debugging reasons, so it is not super important if it is lost. So we initialize it to -1\n                // and update it once the actual transaction completed.\n                let mut tx = self.begin().await?;\n                execute_migration(&mut tx, table_name, migration).await?;\n                tx.commit().await?;\n            }\n\n            // Update `elapsed_time`.\n            // NOTE: The process may disconnect/die at this point, so the elapsed time value might be lost. We accept\n            //       this small risk since this value is not super important.\n            let elapsed = start.elapsed();\n\n            // language=SQL\n            #[allow(clippy::cast_possible_truncation)]\n            let _ = query(AssertSqlSafe(format!(\n                r#\"\n    UPDATE {table_name}\n    SET execution_time = $1\n    WHERE version = $2\n                \"#\n            )))\n            .bind(elapsed.as_nanos() as i64)\n            .bind(migration.version)\n            .execute(self)\n            .await?;\n\n            Ok(elapsed)\n        })\n    }\n\n    fn revert<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async move {\n            let start = Instant::now();\n\n            // execute migration queries\n            if migration.no_tx {\n                revert_migration(self, table_name, migration).await?;\n            } else {\n                // Use a single transaction for the actual migration script and the essential bookkeeping so we never\n                // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.\n                let mut tx = self.begin().await?;\n                revert_migration(&mut tx, table_name, migration).await?;\n                tx.commit().await?;\n            }\n\n            let elapsed = start.elapsed();\n\n            Ok(elapsed)\n        })\n    }\n}\n\nasync fn execute_migration(\n    conn: &mut PgConnection,\n    table_name: &str,\n    migration: &Migration,\n) -> Result<(), MigrateError> {\n    let _ = conn\n        .execute(migration.sql.clone())\n        .await\n        .map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;\n\n    // language=SQL\n    let _ = query(AssertSqlSafe(format!(\n        r#\"\n    INSERT INTO {table_name} ( version, description, success, checksum, execution_time )\n    VALUES ( $1, $2, TRUE, $3, -1 )\n                \"#\n    )))\n    .bind(migration.version)\n    .bind(&*migration.description)\n    .bind(&*migration.checksum)\n    .execute(conn)\n    .await?;\n\n    Ok(())\n}\n\nasync fn revert_migration(\n    conn: &mut PgConnection,\n    table_name: &str,\n    migration: &Migration,\n) -> Result<(), MigrateError> {\n    let _ = conn\n        .execute(migration.sql.clone())\n        .await\n        .map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;\n\n    // language=SQL\n    let _ = query(AssertSqlSafe(format!(\n        r#\"DELETE FROM {table_name} WHERE version = $1\"#\n    )))\n    .bind(migration.version)\n    .execute(conn)\n    .await?;\n\n    Ok(())\n}\n\nasync fn current_database(conn: &mut PgConnection) -> Result<String, MigrateError> {\n    // language=SQL\n    Ok(query_scalar(\"SELECT current_database()\")\n        .fetch_one(conn)\n        .await?)\n}\n\n// inspired from rails: https://github.com/rails/rails/blob/6e49cc77ab3d16c06e12f93158eaf3e507d4120e/activerecord/lib/active_record/migration.rb#L1308\nfn generate_lock_id(database_name: &str) -> i64 {\n    const CRC_IEEE: crc::Crc<u32> = crc::Crc::<u32>::new(&crc::CRC_32_ISO_HDLC);\n    // 0x3d32ad9e chosen by fair dice roll\n    0x3d32ad9e * (CRC_IEEE.checksum(database_name.as_bytes()) as i64)\n}\n"
  },
  {
    "path": "sqlx-postgres/src/options/connect.rs",
    "content": "use crate::connection::ConnectOptions;\nuse crate::error::Error;\nuse crate::{PgConnectOptions, PgConnection};\nuse log::LevelFilter;\nuse sqlx_core::Url;\nuse std::future::Future;\nuse std::time::Duration;\n\nimpl ConnectOptions for PgConnectOptions {\n    type Connection = PgConnection;\n\n    fn from_url(url: &Url) -> Result<Self, Error> {\n        Self::parse_from_url(url)\n    }\n\n    fn to_url_lossy(&self) -> Url {\n        self.build_url()\n    }\n\n    fn connect(&self) -> impl Future<Output = Result<Self::Connection, Error>> + Send + '_\n    where\n        Self::Connection: Sized,\n    {\n        PgConnection::establish(self)\n    }\n\n    fn log_statements(mut self, level: LevelFilter) -> Self {\n        self.log_settings.log_statements(level);\n        self\n    }\n\n    fn log_slow_statements(mut self, level: LevelFilter, duration: Duration) -> Self {\n        self.log_settings.log_slow_statements(level, duration);\n        self\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/options/doc.md",
    "content": "Options and flags which can be used to configure a PostgreSQL connection.\n\nA value of `PgConnectOptions` can be parsed from a connection URL,\nas described by [libpq][libpq-connstring].\n\nThe general form for a connection URL is:\n\n```text\npostgresql://[user[:password]@][host][:port][/dbname][?param1=value1&...]\n```\n\nThe URL scheme designator can be either `postgresql://` or `postgres://`.\nEach of the URL parts is optional. For defaults, see the next section.\n\nThis type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string\ncontaining a connection URL and then further adjust options if necessary (see example below).\n\nNote that characters not allowed in URLs must be [percent-encoded].\n\n# Parameters\n\nThis API accepts many of the same parameters as [libpq][libpq-params];\nif a parameter is not passed in via URL, it is populated by reading\n[environment variables][libpq-envars] or choosing customary defaults.\n\n| Parameter          | Environment Variable | Default / Remarks                                           |\n|--------------------|----------------------|-------------------------------------------------------------|\n| `user`             | `PGUSER`             | The `whoami` of the currently running process.              |\n| `password`         | `PGPASSWORD`         | Read from [`passfile`], if it exists.                       |\n| [`passfile`]       | `PGPASSFILE`         | `~/.pgpass` or `%APPDATA%\\postgresql\\pgpass.conf` (Windows) |\n| `host`             | `PGHOST`             | See [Note: Default Host](#note-default-host).               |\n| `hostaddr`         | `PGHOSTADDR`         | See [Note: Default Host](#note-default-host).               |\n| `port`             | `PGPORT`             | `5432`                                                      |\n| `dbname`           | `PGDATABASE`         | Unset; defaults to the username server-side.                |\n| `sslmode`          | `PGSSLMODE`          | `prefer`. See [`PgSslMode`] for details.                    |\n| `sslrootcert`      | `PGSSLROOTCERT`      | Unset. See [Note: SSL](#note-ssl).                          |\n| `sslcert`          | `PGSSLCERT`          | Unset. See [Note: SSL](#note-ssl).                          |\n| `sslkey`           | `PGSSLKEY`           | Unset. See [Note: SSL](#note-ssl).                          |\n| `options`          | `PGOPTIONS`          | Unset.                                                      |\n| `application_name` | `PGAPPNAME`          | Unset.                                                      |\n\n[`passfile`] handling may be bypassed using [`PgConnectOptions::new_without_pgpass()`].\n\n## SQLx-Specific\nSQLx also parses some bespoke parameters. These are _not_ configurable by environment variable.\nInstead, the name is linked to the method to set the value.\n\n| Parameter                                                    | Default                       |\n|--------------------------------------------------------------|-------------------------------|\n| [`statement-cache-capacity`][Self::statement_cache_capacity] | `100`                         |\n\n# Example URLs\n```text\npostgresql://\npostgresql://:5433\npostgresql://localhost\npostgresql://localhost:5433\npostgresql://localhost/mydb\npostgresql://user@localhost\npostgresql://user:secret@localhost\npostgresql://user:correct%20horse%20battery%20staple@localhost\npostgresql://localhost?dbname=mydb&user=postgres&password=postgres\n```\n\nSee also [Note: Unix Domain Sockets](#note-unix-domain-sockets) below.\n\n# Note: Default Host\nIf the connection URL does not contain a hostname and `PGHOST` is not set,\nthis constructor looks for an open Unix domain socket in one of a few standard locations\n(configured when Postgres is built):\n\n* `/var/run/postgresql/.s.PGSQL.{port}` (Debian)\n* `/private/tmp/.s.PGSQL.{port}` (macOS when installed through Homebrew)\n* `/tmp/.s.PGSQL.{port}` (default otherwise)\n\nThis depends on the value of `port` being correct.\nIf Postgres is using a port other than the default (`5432`), `port` must be set.\n\nIf no Unix domain socket is found, `localhost` is assumed.\n\nNote: this description is updated on a best-effort basis.\nSee `default_host()` in the same source file as this method for the current behavior.\n\n# Note: SSL\n## Root Certs\nIf `sslrootcert` is not set, the default root certificates used depends on Cargo features:\n\n* If `tls-native-tls` is enabled, the system root certificates are used.\n* If `tls-rustls-ring-native-roots` is enabled, the system root certificates are used.\n* Otherwise, TLS roots are populated using the [`webpki-roots`] crate.\n\n## Environment Variables\nUnlike with `libpq`, the following environment variables may be _either_\na path to a file _or_ a string value containing a [PEM-encoded value][rfc7468]:\n\n* `PGSSLROOTCERT`\n* `PGSSLCERT`\n* `PGSSLKEY`\n\nIf the string begins with the standard `-----BEGIN <CERTIFICATE | PRIVATE KEY>-----` header\nand ends with the standard `-----END <CERTIFICATE | PRIVATE KEY>-----` footer,\nit is parsed directly.\n\nThis behavior is _only_ implemented for the environment variables, not the URL parameters.\n\nNote: passing the SSL private key via environment variable may be a security risk.\n\n# Note: Unix Domain Sockets\nIf you want to connect to Postgres over a Unix domain socket, you can pass the path\nto the _directory_ containing the socket as the `host` parameter.\n\nThe final path to the socket will be `{host}/.s.PGSQL.{port}` as is standard for Postgres.\n\nIf you're passing the domain socket path as the host segment of the URL, forward slashes\nin the path must be [percent-encoded] (replacing `/` with `%2F`), e.g.:\n\n```text\npostgres://%2Fvar%2Frun%2Fpostgresql/dbname\n\nDifferent port:\npostgres://%2Fvar%2Frun%2Fpostgresql:5433/dbname\n\nWith username and password:\npostgres://user:password@%2Fvar%2Frun%2Fpostgresql/dbname\n\nWith username and password, and different port:\npostgres://user:password@%2Fvar%2Frun%2Fpostgresql:5432/dbname\n```\n\nInstead, the hostname can be passed in the query segment of the URL,\nwhich does not require forward-slashes to be percent-encoded\n(however, [other characters are][percent-encoded]):\n\n```text\npostgres:dbname?host=/var/run/postgresql\n\nDifferent port:\npostgres://:5433/dbname?host=/var/run/postgresql\n\nWith username and password:\npostgres://user:password@/dbname?host=/var/run/postgresql\n\nWith username and password, and different port:\npostgres://user:password@:5433/dbname?host=/var/run/postgresql\n```\n\n# Example\n\n```rust,no_run\nuse sqlx::{Connection, ConnectOptions};\nuse sqlx::postgres::{PgConnectOptions, PgConnection, PgPool, PgSslMode};\n\n# async fn example() -> sqlx::Result<()> {\n// URL connection string\nlet conn = PgConnection::connect(\"postgres://localhost/mydb\").await?;\n\n// Manually-constructed options\nlet conn = PgConnectOptions::new()\n    .host(\"secret-host\")\n    .port(2525)\n    .username(\"secret-user\")\n    .password(\"secret-password\")\n    .ssl_mode(PgSslMode::Require)\n    .connect()\n    .await?;\n\n// Modifying options parsed from a string\nlet mut opts: PgConnectOptions = \"postgres://localhost/mydb\".parse()?;\n\n// Change the log verbosity level for queries.\n// Information about SQL queries is logged at `DEBUG` level by default.\nopts = opts.log_statements(log::LevelFilter::Trace);\n\nlet pool = PgPool::connect_with(opts).await?;\n# Ok(())\n# }\n```\n\n[percent-encoded]: https://developer.mozilla.org/en-US/docs/Glossary/Percent-encoding\n[`passfile`]: https://www.postgresql.org/docs/current/libpq-pgpass.html\n[libpq-connstring]: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING\n[libpq-params]: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS\n[libpq-envars]: https://www.postgresql.org/docs/current/libpq-envars.html\n[rfc7468]: https://datatracker.ietf.org/doc/html/rfc7468\n[`webpki-roots`]: https://docs.rs/webpki-roots"
  },
  {
    "path": "sqlx-postgres/src/options/mod.rs",
    "content": "use std::borrow::Cow;\nuse std::env::var;\nuse std::fmt::{self, Display, Write};\nuse std::path::{Path, PathBuf};\n\npub use ssl_mode::PgSslMode;\n\nuse crate::{connection::LogSettings, net::tls::CertificateInput};\n\nmod connect;\nmod parse;\nmod pgpass;\nmod ssl_mode;\n\n#[doc = include_str!(\"doc.md\")]\n#[derive(Debug, Clone)]\npub struct PgConnectOptions {\n    pub(crate) host: String,\n    pub(crate) port: u16,\n    pub(crate) socket: Option<PathBuf>,\n    pub(crate) username: String,\n    pub(crate) password: Option<String>,\n    pub(crate) database: Option<String>,\n    pub(crate) ssl_mode: PgSslMode,\n    pub(crate) ssl_root_cert: Option<CertificateInput>,\n    pub(crate) ssl_client_cert: Option<CertificateInput>,\n    pub(crate) ssl_client_key: Option<CertificateInput>,\n    pub(crate) statement_cache_capacity: usize,\n    pub(crate) application_name: Option<String>,\n    pub(crate) log_settings: LogSettings,\n    pub(crate) extra_float_digits: Option<Cow<'static, str>>,\n    pub(crate) options: Option<String>,\n}\n\nimpl Default for PgConnectOptions {\n    fn default() -> Self {\n        Self::new_without_pgpass().apply_pgpass()\n    }\n}\n\nimpl PgConnectOptions {\n    /// Create a default set of connection options populated from the current environment.\n    ///\n    /// This behaves as if parsed from the connection string `postgres://`\n    ///\n    /// See the type-level documentation for details.\n    pub fn new() -> Self {\n        Self::new_without_pgpass().apply_pgpass()\n    }\n\n    /// Create a default set of connection options _without_ reading from `passfile`.\n    ///\n    /// Equivalent to [`PgConnectOptions::new()`] but `passfile` is ignored.\n    ///\n    /// See the type-level documentation for details.\n    pub fn new_without_pgpass() -> Self {\n        let port = var(\"PGPORT\")\n            .ok()\n            .and_then(|v| v.parse().ok())\n            .unwrap_or(5432);\n\n        let host = var(\"PGHOSTADDR\")\n            .ok()\n            .or_else(|| var(\"PGHOST\").ok())\n            .unwrap_or_else(|| default_host(port));\n\n        let username = if let Ok(username) = var(\"PGUSER\") {\n            username\n        } else if let Ok(username) = whoami::username() {\n            username\n        } else {\n            // keep the same fallback as previous version\n            \"unknown\".to_string()\n        };\n\n        let database = var(\"PGDATABASE\").ok();\n\n        PgConnectOptions {\n            port,\n            host,\n            socket: None,\n            username,\n            password: var(\"PGPASSWORD\").ok(),\n            database,\n            ssl_root_cert: var(\"PGSSLROOTCERT\").ok().map(CertificateInput::from),\n            ssl_client_cert: var(\"PGSSLCERT\").ok().map(CertificateInput::from),\n            // As of writing, the implementation of `From<String>` only looks for\n            // `-----BEGIN CERTIFICATE-----` and so will not attempt to parse\n            // a PEM-encoded private key.\n            ssl_client_key: var(\"PGSSLKEY\").ok().map(CertificateInput::from),\n            ssl_mode: var(\"PGSSLMODE\")\n                .ok()\n                .and_then(|v| v.parse().ok())\n                .unwrap_or_default(),\n            statement_cache_capacity: 100,\n            application_name: var(\"PGAPPNAME\").ok(),\n            extra_float_digits: Some(\"2\".into()),\n            log_settings: Default::default(),\n            options: var(\"PGOPTIONS\").ok(),\n        }\n    }\n\n    pub(crate) fn apply_pgpass(mut self) -> Self {\n        if self.password.is_none() {\n            self.password = pgpass::load_password(\n                &self.host,\n                self.port,\n                &self.username,\n                self.database.as_deref(),\n            );\n        }\n\n        self\n    }\n\n    /// Sets the name of the host to connect to.\n    ///\n    /// If a host name begins with a slash, it specifies\n    /// Unix-domain communication rather than TCP/IP communication; the value is the name of\n    /// the directory in which the socket file is stored.\n    ///\n    /// The default behavior when host is not specified, or is empty,\n    /// is to connect to a Unix-domain socket\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .host(\"localhost\");\n    /// ```\n    pub fn host(mut self, host: &str) -> Self {\n        host.clone_into(&mut self.host);\n        self\n    }\n\n    /// Sets the port to connect to at the server host.\n    ///\n    /// The default port for PostgreSQL is `5432`.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .port(5432);\n    /// ```\n    pub fn port(mut self, port: u16) -> Self {\n        self.port = port;\n        self\n    }\n\n    /// Sets a custom path to a directory containing a unix domain socket,\n    /// switching the connection method from TCP to the corresponding socket.\n    ///\n    /// By default set to `None`.\n    pub fn socket(mut self, path: impl AsRef<Path>) -> Self {\n        self.socket = Some(path.as_ref().to_path_buf());\n        self\n    }\n\n    /// Sets the username to connect as.\n    ///\n    /// Defaults to be the same as the operating system name of\n    /// the user running the application.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .username(\"postgres\");\n    /// ```\n    pub fn username(mut self, username: &str) -> Self {\n        username.clone_into(&mut self.username);\n        self\n    }\n\n    /// Sets the password to use if the server demands password authentication.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .username(\"root\")\n    ///     .password(\"safe-and-secure\");\n    /// ```\n    pub fn password(mut self, password: &str) -> Self {\n        self.password = Some(password.to_owned());\n        self\n    }\n\n    /// Sets the database name. Defaults to be the same as the user name.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .database(\"postgres\");\n    /// ```\n    pub fn database(mut self, database: &str) -> Self {\n        self.database = Some(database.to_owned());\n        self\n    }\n\n    /// Sets whether or with what priority a secure SSL TCP/IP connection will be negotiated\n    /// with the server.\n    ///\n    /// By default, the SSL mode is [`Prefer`](PgSslMode::Prefer), and the client will\n    /// first attempt an SSL connection but fallback to a non-SSL connection on failure.\n    ///\n    /// Ignored for Unix domain socket communication.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    /// let options = PgConnectOptions::new()\n    ///     .ssl_mode(PgSslMode::Require);\n    /// ```\n    pub fn ssl_mode(mut self, mode: PgSslMode) -> Self {\n        self.ssl_mode = mode;\n        self\n    }\n\n    /// Sets the name of a file containing SSL certificate authority (CA) certificate(s).\n    /// If the file exists, the server's certificate will be verified to be signed by\n    /// one of these authorities.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    /// let options = PgConnectOptions::new()\n    ///     // Providing a CA certificate with less than VerifyCa is pointless\n    ///     .ssl_mode(PgSslMode::VerifyCa)\n    ///     .ssl_root_cert(\"./ca-certificate.crt\");\n    /// ```\n    pub fn ssl_root_cert(mut self, cert: impl AsRef<Path>) -> Self {\n        self.ssl_root_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf()));\n        self\n    }\n\n    /// Sets the name of a file containing SSL client certificate.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    /// let options = PgConnectOptions::new()\n    ///     // Providing a CA certificate with less than VerifyCa is pointless\n    ///     .ssl_mode(PgSslMode::VerifyCa)\n    ///     .ssl_client_cert(\"./client.crt\");\n    /// ```\n    pub fn ssl_client_cert(mut self, cert: impl AsRef<Path>) -> Self {\n        self.ssl_client_cert = Some(CertificateInput::File(cert.as_ref().to_path_buf()));\n        self\n    }\n\n    /// Sets the SSL client certificate as a PEM-encoded byte slice.\n    ///\n    /// This should be an ASCII-encoded blob that starts with `-----BEGIN CERTIFICATE-----`.\n    ///\n    /// # Example\n    /// Note: embedding SSL certificates and keys in the binary is not advised.\n    /// This is for illustration purposes only.\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    ///\n    /// const CERT: &[u8] = b\"\\\n    /// -----BEGIN CERTIFICATE-----\n    /// <Certificate data here.>\n    /// -----END CERTIFICATE-----\";\n    ///    \n    /// let options = PgConnectOptions::new()\n    ///     // Providing a CA certificate with less than VerifyCa is pointless\n    ///     .ssl_mode(PgSslMode::VerifyCa)\n    ///     .ssl_client_cert_from_pem(CERT);\n    /// ```\n    pub fn ssl_client_cert_from_pem(mut self, cert: impl AsRef<[u8]>) -> Self {\n        self.ssl_client_cert = Some(CertificateInput::Inline(cert.as_ref().to_vec()));\n        self\n    }\n\n    /// Sets the name of a file containing SSL client key.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    /// let options = PgConnectOptions::new()\n    ///     // Providing a CA certificate with less than VerifyCa is pointless\n    ///     .ssl_mode(PgSslMode::VerifyCa)\n    ///     .ssl_client_key(\"./client.key\");\n    /// ```\n    pub fn ssl_client_key(mut self, key: impl AsRef<Path>) -> Self {\n        self.ssl_client_key = Some(CertificateInput::File(key.as_ref().to_path_buf()));\n        self\n    }\n\n    /// Sets the SSL client key as a PEM-encoded byte slice.\n    ///\n    /// This should be an ASCII-encoded blob that starts with `-----BEGIN PRIVATE KEY-----`.\n    ///\n    /// # Example\n    /// Note: embedding SSL certificates and keys in the binary is not advised.\n    /// This is for illustration purposes only.\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    ///\n    /// const KEY: &[u8] = b\"\\\n    /// -----BEGIN PRIVATE KEY-----\n    /// <Private key data here.>\n    /// -----END PRIVATE KEY-----\";\n    ///\n    /// let options = PgConnectOptions::new()\n    ///     // Providing a CA certificate with less than VerifyCa is pointless\n    ///     .ssl_mode(PgSslMode::VerifyCa)\n    ///     .ssl_client_key_from_pem(KEY);\n    /// ```\n    pub fn ssl_client_key_from_pem(mut self, key: impl AsRef<[u8]>) -> Self {\n        self.ssl_client_key = Some(CertificateInput::Inline(key.as_ref().to_vec()));\n        self\n    }\n\n    /// Sets PEM encoded trusted SSL Certificate Authorities (CA).\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgSslMode, PgConnectOptions};\n    /// let options = PgConnectOptions::new()\n    ///     // Providing a CA certificate with less than VerifyCa is pointless\n    ///     .ssl_mode(PgSslMode::VerifyCa)\n    ///     .ssl_root_cert_from_pem(vec![]);\n    /// ```\n    pub fn ssl_root_cert_from_pem(mut self, pem_certificate: Vec<u8>) -> Self {\n        self.ssl_root_cert = Some(CertificateInput::Inline(pem_certificate));\n        self\n    }\n\n    /// Sets the capacity of the connection's statement cache in a number of stored\n    /// distinct statements. Caching is handled using LRU, meaning when the\n    /// amount of queries hits the defined limit, the oldest statement will get\n    /// dropped.\n    ///\n    /// The default cache capacity is 100 statements.\n    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {\n        self.statement_cache_capacity = capacity;\n        self\n    }\n\n    /// Sets the application name. Defaults to None\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .application_name(\"my-app\");\n    /// ```\n    pub fn application_name(mut self, application_name: &str) -> Self {\n        self.application_name = Some(application_name.to_owned());\n        self\n    }\n\n    /// Sets or removes the `extra_float_digits` connection option.\n    ///\n    /// This changes the default precision of floating-point values returned in text mode (when\n    /// not using prepared statements such as calling methods of [`Executor`] directly).\n    ///\n    /// Historically, Postgres would by default round floating-point values to 6 and 15 digits\n    /// for `float4`/`REAL` (`f32`) and `float8`/`DOUBLE` (`f64`), respectively, which would mean\n    /// that the returned value may not be exactly the same as its representation in Postgres.\n    ///\n    /// The nominal range for this value is `-15` to `3`, where negative values for this option\n    /// cause floating-points to be rounded to that many fewer digits than normal (`-1` causes\n    /// `float4` to be rounded to 5 digits instead of six, or 14 instead of 15 for `float8`),\n    /// positive values cause Postgres to emit that many extra digits of precision over default\n    /// (or simply use maximum precision in Postgres 12 and later),\n    /// and 0 means keep the default behavior (or the \"old\" behavior described above\n    /// as of Postgres 12).\n    ///\n    /// SQLx sets this value to 3 by default, which tells Postgres to return floating-point values\n    /// at their maximum precision in the hope that the parsed value will be identical to its\n    /// counterpart in Postgres. This is also the default in Postgres 12 and later anyway.\n    ///\n    /// However, older versions of Postgres and alternative implementations that talk the Postgres\n    /// protocol may not support this option, or the full range of values.\n    ///\n    /// If you get an error like \"unknown option `extra_float_digits`\" when connecting, try\n    /// setting this to `None` or consult the manual of your database for the allowed range\n    /// of values.\n    ///\n    /// For more information, see:\n    /// * [Postgres manual, 20.11.2: Client Connection Defaults; Locale and Formatting][20.11.2]\n    /// * [Postgres manual, 8.1.3: Numeric Types; Floating-point Types][8.1.3]\n    ///\n    /// [`Executor`]: crate::executor::Executor\n    /// [20.11.2]: https://www.postgresql.org/docs/current/runtime-config-client.html#RUNTIME-CONFIG-CLIENT-FORMAT\n    /// [8.1.3]: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT\n    ///\n    /// ### Examples\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    ///\n    /// let mut options = PgConnectOptions::new()\n    ///     // for Redshift and Postgres 10\n    ///     .extra_float_digits(2);\n    ///\n    /// let mut options = PgConnectOptions::new()\n    ///     // don't send the option at all (Postgres 9 and older)\n    ///     .extra_float_digits(None);\n    /// ```\n    pub fn extra_float_digits(mut self, extra_float_digits: impl Into<Option<i8>>) -> Self {\n        self.extra_float_digits = extra_float_digits.into().map(|it| it.to_string().into());\n        self\n    }\n\n    /// Set additional startup options for the connection as a list of key-value pairs.\n    ///\n    /// Escapes the options’ backslash and space characters as per\n    /// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .options([(\"geqo\", \"off\"), (\"statement_timeout\", \"5min\")]);\n    /// ```\n    pub fn options<K, V, I>(mut self, options: I) -> Self\n    where\n        K: Display,\n        V: Display,\n        I: IntoIterator<Item = (K, V)>,\n    {\n        // Do this in here so `options_str` is only set if we have an option to insert\n        let options_str = self.options.get_or_insert_with(String::new);\n        for (k, v) in options {\n            if !options_str.is_empty() {\n                options_str.push(' ');\n            }\n\n            options_str.push_str(\"-c \");\n            write!(PgOptionsWriteEscaped(options_str), \"{k}={v}\").ok();\n        }\n        self\n    }\n\n    /// We try using a socket if hostname starts with `/` or if socket parameter\n    /// is specified.\n    pub(crate) fn fetch_socket(&self) -> Option<String> {\n        match self.socket {\n            Some(ref socket) => {\n                let full_path = format!(\"{}/.s.PGSQL.{}\", socket.display(), self.port);\n                Some(full_path)\n            }\n            None if self.host.starts_with('/') => {\n                let full_path = format!(\"{}/.s.PGSQL.{}\", self.host, self.port);\n                Some(full_path)\n            }\n            _ => None,\n        }\n    }\n}\n\nimpl PgConnectOptions {\n    /// Get the current host.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .host(\"127.0.0.1\");\n    /// assert_eq!(options.get_host(), \"127.0.0.1\");\n    /// ```\n    pub fn get_host(&self) -> &str {\n        &self.host\n    }\n\n    /// Get the server's port.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .port(6543);\n    /// assert_eq!(options.get_port(), 6543);\n    /// ```\n    pub fn get_port(&self) -> u16 {\n        self.port\n    }\n\n    /// Get the socket path.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .socket(\"/tmp\");\n    /// assert!(options.get_socket().is_some());\n    /// ```\n    pub fn get_socket(&self) -> Option<&PathBuf> {\n        self.socket.as_ref()\n    }\n\n    /// Get the server's port.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .username(\"foo\");\n    /// assert_eq!(options.get_username(), \"foo\");\n    /// ```\n    pub fn get_username(&self) -> &str {\n        &self.username\n    }\n\n    /// Get the current database name.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .database(\"postgres\");\n    /// assert!(options.get_database().is_some());\n    /// ```\n    pub fn get_database(&self) -> Option<&str> {\n        self.database.as_deref()\n    }\n\n    /// Get the SSL mode.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::{PgConnectOptions, PgSslMode};\n    /// let options = PgConnectOptions::new();\n    /// assert!(matches!(options.get_ssl_mode(), PgSslMode::Prefer));\n    /// ```\n    pub fn get_ssl_mode(&self) -> PgSslMode {\n        self.ssl_mode\n    }\n\n    /// Get the application name.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .application_name(\"service\");\n    /// assert!(options.get_application_name().is_some());\n    /// ```\n    pub fn get_application_name(&self) -> Option<&str> {\n        self.application_name.as_deref()\n    }\n\n    /// Get the options.\n    ///\n    /// # Example\n    ///\n    /// ```rust\n    /// # use sqlx_postgres::PgConnectOptions;\n    /// let options = PgConnectOptions::new()\n    ///     .options([(\"foo\", \"bar\")]);\n    /// assert!(options.get_options().is_some());\n    /// ```\n    pub fn get_options(&self) -> Option<&str> {\n        self.options.as_deref()\n    }\n}\n\nfn default_host(port: u16) -> String {\n    // try to check for the existence of a unix socket and uses that\n    let socket = format!(\".s.PGSQL.{port}\");\n    let candidates = [\n        \"/var/run/postgresql\", // Debian\n        \"/private/tmp\",        // OSX (homebrew)\n        \"/tmp\",                // Default\n    ];\n\n    for candidate in &candidates {\n        if Path::new(candidate).join(&socket).exists() {\n            return candidate.to_string();\n        }\n    }\n\n    // fallback to localhost if no socket was found\n    \"localhost\".to_owned()\n}\n\n/// Writer that escapes passed-in PostgreSQL options.\n///\n/// Escapes backslashes and spaces with an additional backslash according to\n/// https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS\n#[derive(Debug)]\nstruct PgOptionsWriteEscaped<'a>(&'a mut String);\n\nimpl Write for PgOptionsWriteEscaped<'_> {\n    fn write_str(&mut self, s: &str) -> fmt::Result {\n        let mut span_start = 0;\n\n        for (span_end, matched) in s.match_indices([' ', '\\\\']) {\n            write!(self.0, r\"{}\\{matched}\", &s[span_start..span_end])?;\n            span_start = span_end + matched.len();\n        }\n\n        // Write the rest of the string after the last match, or all of it if no matches\n        self.0.push_str(&s[span_start..]);\n\n        Ok(())\n    }\n\n    fn write_char(&mut self, ch: char) -> fmt::Result {\n        if matches!(ch, ' ' | '\\\\') {\n            self.0.push('\\\\');\n        }\n\n        self.0.push(ch);\n\n        Ok(())\n    }\n}\n\n#[test]\nfn test_options_formatting() {\n    let options = PgConnectOptions::new().options([(\"geqo\", \"off\")]);\n    assert_eq!(options.options, Some(\"-c geqo=off\".to_string()));\n    let options = options.options([(\"search_path\", \"sqlx\")]);\n    assert_eq!(\n        options.options,\n        Some(\"-c geqo=off -c search_path=sqlx\".to_string())\n    );\n    let options = PgConnectOptions::new().options([(\"geqo\", \"off\"), (\"statement_timeout\", \"5min\")]);\n    assert_eq!(\n        options.options,\n        Some(\"-c geqo=off -c statement_timeout=5min\".to_string())\n    );\n    // https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS\n    let options =\n        PgConnectOptions::new().options([(\"application_name\", r\"/back\\slash/ and\\ spaces\")]);\n    assert_eq!(\n        options.options,\n        Some(r\"-c application_name=/back\\\\slash/\\ and\\\\\\ spaces\".to_string())\n    );\n    let options = PgConnectOptions::new();\n    assert_eq!(options.options, None);\n}\n\n#[test]\nfn test_pg_write_escaped() {\n    let mut buf = String::new();\n    let mut x = PgOptionsWriteEscaped(&mut buf);\n    x.write_str(\"x\").unwrap();\n    x.write_str(\"\").unwrap();\n    x.write_char('\\\\').unwrap();\n    x.write_str(\"y \\\\\").unwrap();\n    x.write_char(' ').unwrap();\n    x.write_char('z').unwrap();\n    assert_eq!(buf, r\"x\\\\y\\ \\\\\\ z\");\n}\n"
  },
  {
    "path": "sqlx-postgres/src/options/parse.rs",
    "content": "use crate::error::Error;\nuse crate::{PgConnectOptions, PgSslMode};\nuse sqlx_core::percent_encoding::{percent_decode_str, utf8_percent_encode, NON_ALPHANUMERIC};\nuse sqlx_core::Url;\nuse std::net::IpAddr;\nuse std::str::FromStr;\n\nimpl PgConnectOptions {\n    pub(crate) fn parse_from_url(url: &Url) -> Result<Self, Error> {\n        let mut options = Self::new_without_pgpass();\n\n        if let Some(host) = url.host_str() {\n            let host_decoded = percent_decode_str(host);\n            options = match host_decoded.clone().next() {\n                Some(b'/') => options.socket(&*host_decoded.decode_utf8().map_err(Error::config)?),\n                _ => options.host(host),\n            }\n        }\n\n        if let Some(port) = url.port() {\n            options = options.port(port);\n        }\n\n        let username = url.username();\n        if !username.is_empty() {\n            options = options.username(\n                &percent_decode_str(username)\n                    .decode_utf8()\n                    .map_err(Error::config)?,\n            );\n        }\n\n        if let Some(password) = url.password() {\n            options = options.password(\n                &percent_decode_str(password)\n                    .decode_utf8()\n                    .map_err(Error::config)?,\n            );\n        }\n\n        let path = url.path().trim_start_matches('/');\n        if !path.is_empty() {\n            options = options.database(\n                &percent_decode_str(path)\n                    .decode_utf8()\n                    .map_err(Error::config)?,\n            );\n        }\n\n        for (key, value) in url.query_pairs().into_iter() {\n            match &*key {\n                \"sslmode\" | \"ssl-mode\" => {\n                    options = options.ssl_mode(value.parse().map_err(Error::config)?);\n                }\n\n                \"sslrootcert\" | \"ssl-root-cert\" | \"ssl-ca\" => {\n                    options = options.ssl_root_cert(&*value);\n                }\n\n                \"sslcert\" | \"ssl-cert\" => options = options.ssl_client_cert(&*value),\n\n                \"sslkey\" | \"ssl-key\" => options = options.ssl_client_key(&*value),\n\n                \"statement-cache-capacity\" => {\n                    options =\n                        options.statement_cache_capacity(value.parse().map_err(Error::config)?);\n                }\n\n                \"host\" => {\n                    if value.starts_with('/') {\n                        options = options.socket(&*value);\n                    } else {\n                        options = options.host(&value);\n                    }\n                }\n\n                \"hostaddr\" => {\n                    value.parse::<IpAddr>().map_err(Error::config)?;\n                    options = options.host(&value)\n                }\n\n                \"port\" => options = options.port(value.parse().map_err(Error::config)?),\n\n                \"dbname\" => options = options.database(&value),\n\n                \"user\" => options = options.username(&value),\n\n                \"password\" => options = options.password(&value),\n\n                \"application_name\" => options = options.application_name(&value),\n\n                \"options\" => {\n                    if let Some(options) = options.options.as_mut() {\n                        options.push(' ');\n                        options.push_str(&value);\n                    } else {\n                        options.options = Some(value.to_string());\n                    }\n                }\n\n                k if k.starts_with(\"options[\") => {\n                    if let Some(key) = k.strip_prefix(\"options[\").unwrap().strip_suffix(']') {\n                        options = options.options([(key, &*value)]);\n                    }\n                }\n\n                _ => tracing::warn!(%key, %value, \"ignoring unrecognized connect parameter\"),\n            }\n        }\n\n        let options = options.apply_pgpass();\n\n        Ok(options)\n    }\n\n    pub(crate) fn build_url(&self) -> Url {\n        let host = match &self.socket {\n            Some(socket) => {\n                utf8_percent_encode(&socket.to_string_lossy(), NON_ALPHANUMERIC).to_string()\n            }\n            None => self.host.to_owned(),\n        };\n\n        let mut url = Url::parse(&format!(\n            \"postgres://{}@{}:{}\",\n            self.username, host, self.port\n        ))\n        .expect(\"BUG: generated un-parseable URL\");\n\n        if let Some(password) = &self.password {\n            let password = utf8_percent_encode(password, NON_ALPHANUMERIC).to_string();\n            let _ = url.set_password(Some(&password));\n        }\n\n        if let Some(database) = &self.database {\n            url.set_path(database);\n        }\n\n        let ssl_mode = match self.ssl_mode {\n            PgSslMode::Allow => \"allow\",\n            PgSslMode::Disable => \"disable\",\n            PgSslMode::Prefer => \"prefer\",\n            PgSslMode::Require => \"require\",\n            PgSslMode::VerifyCa => \"verify-ca\",\n            PgSslMode::VerifyFull => \"verify-full\",\n        };\n        url.query_pairs_mut().append_pair(\"sslmode\", ssl_mode);\n\n        if let Some(ssl_root_cert) = &self.ssl_root_cert {\n            url.query_pairs_mut()\n                .append_pair(\"sslrootcert\", &ssl_root_cert.to_string());\n        }\n\n        if let Some(ssl_client_cert) = &self.ssl_client_cert {\n            url.query_pairs_mut()\n                .append_pair(\"sslcert\", &ssl_client_cert.to_string());\n        }\n\n        if let Some(ssl_client_key) = &self.ssl_client_key {\n            url.query_pairs_mut()\n                .append_pair(\"sslkey\", &ssl_client_key.to_string());\n        }\n\n        url.query_pairs_mut().append_pair(\n            \"statement-cache-capacity\",\n            &self.statement_cache_capacity.to_string(),\n        );\n\n        url\n    }\n}\n\nimpl FromStr for PgConnectOptions {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        let url: Url = s.parse().map_err(Error::config)?;\n\n        Self::parse_from_url(&url)\n    }\n}\n\n#[test]\nfn it_parses_socket_correctly_from_parameter() {\n    let url = \"postgres:///?host=/var/run/postgres/\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(Some(\"/var/run/postgres/\".into()), opts.socket);\n}\n\n#[test]\nfn it_parses_host_correctly_from_parameter() {\n    let url = \"postgres:///?host=google.database.com\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(None, opts.socket);\n    assert_eq!(\"google.database.com\", &opts.host);\n}\n\n#[test]\nfn it_parses_hostaddr_correctly_from_parameter() {\n    let url = \"postgres:///?hostaddr=8.8.8.8\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(None, opts.socket);\n    assert_eq!(\"8.8.8.8\", &opts.host);\n}\n\n#[test]\nfn it_parses_port_correctly_from_parameter() {\n    let url = \"postgres:///?port=1234\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(None, opts.socket);\n    assert_eq!(1234, opts.port);\n}\n\n#[test]\nfn it_parses_dbname_correctly_from_parameter() {\n    let url = \"postgres:///?dbname=some_db\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(None, opts.socket);\n    assert_eq!(Some(\"some_db\"), opts.database.as_deref());\n}\n\n#[test]\nfn it_parses_user_correctly_from_parameter() {\n    let url = \"postgres:///?user=some_user\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(None, opts.socket);\n    assert_eq!(\"some_user\", opts.username);\n}\n\n#[test]\nfn it_parses_password_correctly_from_parameter() {\n    let url = \"postgres:///?password=some_pass\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(None, opts.socket);\n    assert_eq!(Some(\"some_pass\"), opts.password.as_deref());\n}\n\n#[test]\nfn it_parses_application_name_correctly_from_parameter() {\n    let url = \"postgres:///?application_name=some_name\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(Some(\"some_name\"), opts.application_name.as_deref());\n}\n\n#[test]\nfn it_parses_username_with_at_sign_correctly() {\n    let url = \"postgres://user@hostname:password@hostname:5432/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(\"user@hostname\", &opts.username);\n}\n\n#[test]\nfn it_parses_password_with_non_ascii_chars_correctly() {\n    let url = \"postgres://username:p@ssw0rd@hostname:5432/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(Some(\"p@ssw0rd\".into()), opts.password);\n}\n\n#[test]\nfn it_parses_socket_correctly_percent_encoded() {\n    let url = \"postgres://%2Fvar%2Flib%2Fpostgres/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(Some(\"/var/lib/postgres/\".into()), opts.socket);\n}\n#[test]\nfn it_parses_socket_correctly_with_username_percent_encoded() {\n    let url = \"postgres://some_user@%2Fvar%2Flib%2Fpostgres/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(\"some_user\", opts.username);\n    assert_eq!(Some(\"/var/lib/postgres/\".into()), opts.socket);\n    assert_eq!(Some(\"database\"), opts.database.as_deref());\n}\n#[test]\nfn it_parses_libpq_options_correctly() {\n    let url = \"postgres:///?options=-c%20synchronous_commit%3Doff%20--search_path%3Dpostgres\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(\n        Some(\"-c synchronous_commit=off --search_path=postgres\".into()),\n        opts.options\n    );\n}\n#[test]\nfn it_parses_sqlx_options_correctly() {\n    let url = \"postgres:///?options[synchronous_commit]=off&options[search_path]=postgres\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    assert_eq!(\n        Some(\"-c synchronous_commit=off -c search_path=postgres\".into()),\n        opts.options\n    );\n}\n\n#[test]\nfn it_returns_the_parsed_url_when_socket() {\n    let url = \"postgres://username@%2Fvar%2Flib%2Fpostgres/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    let mut expected_url = Url::parse(url).unwrap();\n    // PgConnectOptions defaults\n    let query_string = \"sslmode=prefer&statement-cache-capacity=100\";\n    let port = 5432;\n    expected_url.set_query(Some(query_string));\n    let _ = expected_url.set_port(Some(port));\n\n    assert_eq!(expected_url, opts.build_url());\n}\n\n#[test]\nfn it_returns_the_parsed_url_when_host() {\n    let url = \"postgres://username:p@ssw0rd@hostname:5432/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    let mut expected_url = Url::parse(url).unwrap();\n    // PgConnectOptions defaults\n    let query_string = \"sslmode=prefer&statement-cache-capacity=100\";\n    expected_url.set_query(Some(query_string));\n\n    assert_eq!(expected_url, opts.build_url());\n}\n\n#[test]\nfn built_url_can_be_parsed() {\n    let url = \"postgres://username:p@ssw0rd@hostname:5432/database\";\n    let opts = PgConnectOptions::from_str(url).unwrap();\n\n    let parsed = PgConnectOptions::from_str(opts.build_url().as_ref());\n\n    assert!(parsed.is_ok());\n}\n"
  },
  {
    "path": "sqlx-postgres/src/options/pgpass.rs",
    "content": "use std::borrow::Cow;\nuse std::env::var_os;\nuse std::fs::File;\nuse std::io::{BufRead, BufReader};\nuse std::path::PathBuf;\n\n/// try to load a password from the various pgpass file locations\npub fn load_password(\n    host: &str,\n    port: u16,\n    username: &str,\n    database: Option<&str>,\n) -> Option<String> {\n    let custom_file = var_os(\"PGPASSFILE\");\n    if let Some(file) = custom_file {\n        if let Some(password) =\n            load_password_from_file(PathBuf::from(file), host, port, username, database)\n        {\n            return Some(password);\n        }\n    }\n\n    #[cfg(not(target_os = \"windows\"))]\n    // home_dir fixed in 1.85 (rust-lang/rust#132515) and un-deprecated in 1.87 (rust-lang/rust#137327)\n    #[allow(deprecated)]\n    let default_file = std::env::home_dir().map(|path| path.join(\".pgpass\"));\n    #[cfg(target_os = \"windows\")]\n    let default_file = {\n        use etcetera::BaseStrategy;\n\n        etcetera::base_strategy::Windows::new()\n            .ok()\n            .map(|basedirs| basedirs.data_dir().join(\"postgres\").join(\"pgpass.conf\"))\n    };\n    load_password_from_file(default_file?, host, port, username, database)\n}\n\n/// try to extract a password from a pgpass file\nfn load_password_from_file(\n    path: PathBuf,\n    host: &str,\n    port: u16,\n    username: &str,\n    database: Option<&str>,\n) -> Option<String> {\n    let file = File::open(&path)\n        .map_err(|e| {\n            match e.kind() {\n                std::io::ErrorKind::NotFound => {\n                    tracing::debug!(\n                        path = %path.display(),\n                        \"`.pgpass` file not found\",\n                    );\n                }\n                _ => {\n                    tracing::warn!(\n                        path = %path.display(),\n                        \"Failed to open `.pgpass` file: {e:?}\",\n                    );\n                }\n            };\n        })\n        .ok()?;\n\n    #[cfg(target_os = \"linux\")]\n    {\n        use std::os::unix::fs::PermissionsExt;\n\n        // check file permissions on linux\n\n        let metadata = file.metadata().ok()?;\n        let permissions = metadata.permissions();\n        let mode = permissions.mode();\n        if mode & 0o77 != 0 {\n            tracing::warn!(\n                path = %path.display(),\n                permissions = format!(\"{mode:o}\"),\n                \"Ignoring path. Permissions are not strict enough\",\n            );\n            return None;\n        }\n    }\n\n    let reader = BufReader::new(file);\n    load_password_from_reader(reader, host, port, username, database)\n}\n\nfn load_password_from_reader(\n    mut reader: impl BufRead,\n    host: &str,\n    port: u16,\n    username: &str,\n    database: Option<&str>,\n) -> Option<String> {\n    let mut line = String::new();\n\n    // https://stackoverflow.com/a/55041833\n    fn trim_newline(s: &mut String) {\n        if s.ends_with('\\n') {\n            s.pop();\n            if s.ends_with('\\r') {\n                s.pop();\n            }\n        }\n    }\n\n    while let Ok(n) = reader.read_line(&mut line) {\n        if n == 0 {\n            break;\n        }\n\n        if line.starts_with('#') {\n            // comment, do nothing\n        } else {\n            // try to load password from line\n            trim_newline(&mut line);\n            if let Some(password) = load_password_from_line(&line, host, port, username, database) {\n                return Some(password);\n            }\n        }\n\n        line.clear();\n    }\n\n    None\n}\n\n/// try to check all fields & extract the password\nfn load_password_from_line(\n    mut line: &str,\n    host: &str,\n    port: u16,\n    username: &str,\n    database: Option<&str>,\n) -> Option<String> {\n    let whole_line = line;\n\n    // Pgpass line ordering: hostname, port, database, username, password\n    // See: https://www.postgresql.org/docs/9.3/libpq-pgpass.html\n    match line.trim_start().chars().next() {\n        None | Some('#') => None,\n        _ => {\n            matches_next_field(whole_line, &mut line, host)?;\n            matches_next_field(whole_line, &mut line, &port.to_string())?;\n            matches_next_field(whole_line, &mut line, database.unwrap_or_default())?;\n            matches_next_field(whole_line, &mut line, username)?;\n            Some(line.to_owned())\n        }\n    }\n}\n\n/// check if the next field matches the provided value\nfn matches_next_field(whole_line: &str, line: &mut &str, value: &str) -> Option<()> {\n    let field = find_next_field(line);\n    match field {\n        Some(field) => {\n            if field == \"*\" || field == value {\n                Some(())\n            } else {\n                None\n            }\n        }\n        None => {\n            tracing::warn!(line = whole_line, \"Malformed line in pgpass file\");\n            None\n        }\n    }\n}\n\n/// extract the next value from a line in a pgpass file\n///\n/// `line` will get updated to point behind the field and delimiter\nfn find_next_field<'a>(line: &mut &'a str) -> Option<Cow<'a, str>> {\n    let mut escaping = false;\n    let mut escaped_string = None;\n    let mut last_added = 0;\n\n    let char_indices = line.char_indices();\n    for (idx, c) in char_indices {\n        if c == ':' && !escaping {\n            let (field, rest) = line.split_at(idx);\n            *line = &rest[1..];\n\n            if let Some(mut escaped_string) = escaped_string {\n                escaped_string += &field[last_added..];\n                return Some(Cow::Owned(escaped_string));\n            } else {\n                return Some(Cow::Borrowed(field));\n            }\n        } else if c == '\\\\' {\n            let s = escaped_string.get_or_insert_with(String::new);\n\n            if escaping {\n                s.push('\\\\');\n            } else {\n                *s += &line[last_added..idx];\n            }\n\n            escaping = !escaping;\n            last_added = idx + 1;\n        } else {\n            escaping = false;\n        }\n    }\n\n    None\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{find_next_field, load_password_from_line, load_password_from_reader};\n    use std::borrow::Cow;\n\n    #[test]\n    fn test_find_next_field() {\n        fn test_case<'a>(mut input: &'a str, result: Option<Cow<'a, str>>, rest: &str) {\n            assert_eq!(find_next_field(&mut input), result);\n            assert_eq!(input, rest);\n        }\n\n        // normal field\n        test_case(\"foo:bar:baz\", Some(Cow::Borrowed(\"foo\")), \"bar:baz\");\n        // \\ escaped\n        test_case(\n            \"foo\\\\\\\\:bar:baz\",\n            Some(Cow::Owned(\"foo\\\\\".to_owned())),\n            \"bar:baz\",\n        );\n        // : escaped\n        test_case(\n            \"foo\\\\::bar:baz\",\n            Some(Cow::Owned(\"foo:\".to_owned())),\n            \"bar:baz\",\n        );\n        // unnecessary escape\n        test_case(\n            \"foo\\\\a:bar:baz\",\n            Some(Cow::Owned(\"fooa\".to_owned())),\n            \"bar:baz\",\n        );\n        // other text after escape\n        test_case(\n            \"foo\\\\\\\\a:bar:baz\",\n            Some(Cow::Owned(\"foo\\\\a\".to_owned())),\n            \"bar:baz\",\n        );\n        // double escape\n        test_case(\n            \"foo\\\\\\\\\\\\\\\\a:bar:baz\",\n            Some(Cow::Owned(\"foo\\\\\\\\a\".to_owned())),\n            \"bar:baz\",\n        );\n        // utf8 support\n        test_case(\"🦀:bar:baz\", Some(Cow::Borrowed(\"🦀\")), \"bar:baz\");\n\n        // missing delimiter (eof)\n        test_case(\"foo\", None, \"foo\");\n        // missing delimiter after escape\n        test_case(\"foo\\\\:\", None, \"foo\\\\:\");\n        // missing delimiter after unused trailing escape\n        test_case(\"foo\\\\\", None, \"foo\\\\\");\n    }\n\n    #[test]\n    fn test_load_password_from_line() {\n        // normal\n        assert_eq!(\n            load_password_from_line(\n                \"localhost:5432:bar:foo:baz\",\n                \"localhost\",\n                5432,\n                \"foo\",\n                Some(\"bar\")\n            ),\n            Some(\"baz\".to_owned())\n        );\n        // wildcard\n        assert_eq!(\n            load_password_from_line(\"*:5432:bar:foo:baz\", \"localhost\", 5432, \"foo\", Some(\"bar\")),\n            Some(\"baz\".to_owned())\n        );\n        // accept wildcard with missing db\n        assert_eq!(\n            load_password_from_line(\"localhost:5432:*:foo:baz\", \"localhost\", 5432, \"foo\", None),\n            Some(\"baz\".to_owned())\n        );\n\n        // doesn't match\n        assert_eq!(\n            load_password_from_line(\n                \"thishost:5432:bar:foo:baz\",\n                \"thathost\",\n                5432,\n                \"foo\",\n                Some(\"bar\")\n            ),\n            None\n        );\n        // malformed entry\n        assert_eq!(\n            load_password_from_line(\n                \"localhost:5432:bar:foo\",\n                \"localhost\",\n                5432,\n                \"foo\",\n                Some(\"bar\")\n            ),\n            None\n        );\n    }\n\n    #[test]\n    fn test_load_password_from_reader() {\n        let file = b\"\\\n            localhost:5432:bar:foo:baz\\n\\\n            # mixed line endings (also a comment!)\\n\\\n            *:5432:bar:foo:baz\\r\\n\\\n            # trailing space, comment with CRLF! \\r\\n\\\n            thishost:5432:bar:foo:baz \\n\\\n            # malformed line \\n\\\n            thathost:5432:foobar:foo\\n\\\n            # missing trailing newline\\n\\\n            localhost:5432:*:foo:baz\n        \";\n\n        // normal\n        assert_eq!(\n            load_password_from_reader(&mut &file[..], \"localhost\", 5432, \"foo\", Some(\"bar\")),\n            Some(\"baz\".to_owned())\n        );\n        // wildcard\n        assert_eq!(\n            load_password_from_reader(&mut &file[..], \"localhost\", 5432, \"foo\", Some(\"foobar\")),\n            Some(\"baz\".to_owned())\n        );\n        // accept wildcard with missing db\n        assert_eq!(\n            load_password_from_reader(&mut &file[..], \"localhost\", 5432, \"foo\", None),\n            Some(\"baz\".to_owned())\n        );\n\n        // doesn't match\n        assert_eq!(\n            load_password_from_reader(&mut &file[..], \"thathost\", 5432, \"foo\", Some(\"foobar\")),\n            None\n        );\n        // malformed entry\n        assert_eq!(\n            load_password_from_reader(&mut &file[..], \"thathost\", 5432, \"foo\", Some(\"foobar\")),\n            None\n        );\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/options/ssl_mode.rs",
    "content": "use crate::error::Error;\nuse std::str::FromStr;\n\n/// Options for controlling the level of protection provided for PostgreSQL SSL connections.\n///\n/// It is used by the [`ssl_mode`](super::PgConnectOptions::ssl_mode) method.\n#[derive(Debug, Clone, Copy, Default)]\npub enum PgSslMode {\n    /// Only try a non-SSL connection.\n    Disable,\n\n    /// First try a non-SSL connection; if that fails, try an SSL connection.\n    Allow,\n\n    /// First try an SSL connection; if that fails, try a non-SSL connection.\n    ///\n    /// This is the default if no other mode is specified.\n    #[default]\n    Prefer,\n\n    /// Only try an SSL connection. If a root CA file is present, verify the connection\n    /// in the same way as if `VerifyCa` was specified.\n    Require,\n\n    /// Only try an SSL connection, and verify that the server certificate is issued by a\n    /// trusted certificate authority (CA).\n    VerifyCa,\n\n    /// Only try an SSL connection; verify that the server certificate is issued by a trusted\n    /// CA and that the requested server host name matches that in the certificate.\n    VerifyFull,\n}\n\nimpl FromStr for PgSslMode {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        Ok(match &*s.to_ascii_lowercase() {\n            \"disable\" => PgSslMode::Disable,\n            \"allow\" => PgSslMode::Allow,\n            \"prefer\" => PgSslMode::Prefer,\n            \"require\" => PgSslMode::Require,\n            \"verify-ca\" => PgSslMode::VerifyCa,\n            \"verify-full\" => PgSslMode::VerifyFull,\n\n            _ => {\n                return Err(Error::Configuration(\n                    format!(\"unknown value {s:?} for `ssl_mode`\").into(),\n                ));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/query_result.rs",
    "content": "use std::iter::{Extend, IntoIterator};\n\n#[derive(Debug, Default)]\npub struct PgQueryResult {\n    pub(super) rows_affected: u64,\n}\n\nimpl PgQueryResult {\n    pub fn rows_affected(&self) -> u64 {\n        self.rows_affected\n    }\n}\n\nimpl Extend<PgQueryResult> for PgQueryResult {\n    fn extend<T: IntoIterator<Item = PgQueryResult>>(&mut self, iter: T) {\n        for elem in iter {\n            self.rows_affected += elem.rows_affected;\n        }\n    }\n}\n\n#[cfg(feature = \"any\")]\nimpl From<PgQueryResult> for sqlx_core::any::AnyQueryResult {\n    fn from(done: PgQueryResult) -> Self {\n        sqlx_core::any::AnyQueryResult {\n            rows_affected: done.rows_affected,\n            last_insert_id: None,\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/row.rs",
    "content": "use crate::column::ColumnIndex;\nuse crate::error::Error;\nuse crate::message::DataRow;\nuse crate::statement::PgStatementMetadata;\nuse crate::value::PgValueFormat;\nuse crate::{PgColumn, PgValueRef, Postgres};\nuse sqlx_core::row::debug_row;\npub(crate) use sqlx_core::row::Row;\nuse std::sync::Arc;\n\n/// Implementation of [`Row`] for PostgreSQL.\npub struct PgRow {\n    pub(crate) data: DataRow,\n    pub(crate) format: PgValueFormat,\n    pub(crate) metadata: Arc<PgStatementMetadata>,\n}\n\nimpl Row for PgRow {\n    type Database = Postgres;\n\n    fn columns(&self) -> &[PgColumn] {\n        &self.metadata.columns\n    }\n\n    fn try_get_raw<I>(&self, index: I) -> Result<PgValueRef<'_>, Error>\n    where\n        I: ColumnIndex<Self>,\n    {\n        let index = index.index(self)?;\n        let column = &self.metadata.columns[index];\n        let value = self.data.get(index);\n\n        Ok(PgValueRef {\n            format: self.format,\n            row: Some(&self.data.storage),\n            type_info: column.type_info.clone(),\n            value,\n        })\n    }\n}\n\nimpl ColumnIndex<PgRow> for &'_ str {\n    fn index(&self, row: &PgRow) -> Result<usize, Error> {\n        row.metadata\n            .column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n\nimpl std::fmt::Debug for PgRow {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        debug_row(self, f)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/statement.rs",
    "content": "use super::{PgColumn, PgTypeInfo};\nuse crate::column::ColumnIndex;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::{PgArguments, Postgres};\nuse std::sync::Arc;\n\nuse sqlx_core::sql_str::SqlStr;\npub(crate) use sqlx_core::statement::Statement;\nuse sqlx_core::{Either, HashMap};\n\n#[derive(Debug, Clone)]\npub struct PgStatement {\n    pub(crate) sql: SqlStr,\n    pub(crate) metadata: Arc<PgStatementMetadata>,\n}\n\n#[derive(Debug, Default)]\npub(crate) struct PgStatementMetadata {\n    pub(crate) columns: Vec<PgColumn>,\n    // This `Arc` is not redundant; it's used to avoid deep-copying this map for the `Any` backend.\n    // See `sqlx-postgres/src/any.rs`\n    pub(crate) column_names: Arc<HashMap<UStr, usize>>,\n    pub(crate) parameters: Vec<PgTypeInfo>,\n}\n\nimpl Statement for PgStatement {\n    type Database = Postgres;\n\n    fn into_sql(self) -> SqlStr {\n        self.sql\n    }\n\n    fn sql(&self) -> &SqlStr {\n        &self.sql\n    }\n\n    fn parameters(&self) -> Option<Either<&[PgTypeInfo], usize>> {\n        Some(Either::Left(&self.metadata.parameters))\n    }\n\n    fn columns(&self) -> &[PgColumn] {\n        &self.metadata.columns\n    }\n\n    impl_statement_query!(PgArguments);\n}\n\nimpl ColumnIndex<PgStatement> for &'_ str {\n    fn index(&self, statement: &PgStatement) -> Result<usize, Error> {\n        statement\n            .metadata\n            .column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n\n// #[cfg(feature = \"any\")]\n// impl<'q> From<PgStatement<'q>> for crate::any::AnyStatement<'q> {\n//     #[inline]\n//     fn from(statement: PgStatement<'q>) -> Self {\n//         crate::any::AnyStatement::<'q> {\n//             columns: statement\n//                 .metadata\n//                 .columns\n//                 .iter()\n//                 .map(|col| col.clone().into())\n//                 .collect(),\n//             column_names: statement.metadata.column_names.clone(),\n//             parameters: Some(Either::Left(\n//                 statement\n//                     .metadata\n//                     .parameters\n//                     .iter()\n//                     .map(|ty| ty.clone().into())\n//                     .collect(),\n//             )),\n//             sql: statement.sql,\n//         }\n//     }\n// }\n"
  },
  {
    "path": "sqlx-postgres/src/testing/mod.rs",
    "content": "use std::future::Future;\nuse std::ops::Deref;\nuse std::str::FromStr;\nuse std::sync::OnceLock;\nuse std::time::Duration;\n\nuse sqlx_core::connection::Connection;\nuse sqlx_core::query_builder::QueryBuilder;\nuse sqlx_core::query_scalar::query_scalar;\nuse sqlx_core::sql_str::AssertSqlSafe;\n\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::pool::{Pool, PoolOptions};\nuse crate::query::query;\nuse crate::{PgConnectOptions, PgConnection, Postgres};\n\npub(crate) use sqlx_core::testing::*;\n\n// Using a blocking `OnceLock` here because the critical sections are short.\nstatic MASTER_POOL: OnceLock<Pool<Postgres>> = OnceLock::new();\n// Automatically delete any databases created before the start of the test binary.\n\nimpl TestSupport for Postgres {\n    fn test_context(\n        args: &TestArgs,\n    ) -> impl Future<Output = Result<TestContext<Self>, Error>> + Send + '_ {\n        test_context(args)\n    }\n\n    async fn cleanup_test(db_name: &str) -> Result<(), Error> {\n        let mut conn = MASTER_POOL\n            .get()\n            .expect(\"cleanup_test() invoked outside `#[sqlx::test]`\")\n            .acquire()\n            .await?;\n\n        do_cleanup(&mut conn, db_name).await\n    }\n\n    async fn cleanup_test_dbs() -> Result<Option<usize>, Error> {\n        let url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n\n        let mut conn = PgConnection::connect(&url).await?;\n\n        let delete_db_names: Vec<String> = query_scalar(\"select db_name from _sqlx_test.databases\")\n            .fetch_all(&mut conn)\n            .await?;\n\n        if delete_db_names.is_empty() {\n            return Ok(None);\n        }\n\n        let mut deleted_db_names = Vec::with_capacity(delete_db_names.len());\n\n        let mut builder = QueryBuilder::new(\"drop database if exists \");\n\n        for db_name in &delete_db_names {\n            builder.push(db_name);\n\n            match builder.build().execute(&mut conn).await {\n                Ok(_deleted) => {\n                    deleted_db_names.push(db_name);\n                }\n                // Assume a database error just means the DB is still in use.\n                Err(Error::Database(dbe)) => {\n                    eprintln!(\"could not clean test database {db_name:?}: {dbe}\")\n                }\n                // Bubble up other errors\n                Err(e) => return Err(e),\n            }\n\n            builder.reset();\n        }\n\n        query(\"delete from _sqlx_test.databases where db_name = any($1::text[])\")\n            .bind(&deleted_db_names)\n            .execute(&mut conn)\n            .await?;\n\n        let _ = conn.close().await;\n        Ok(Some(delete_db_names.len()))\n    }\n\n    async fn snapshot(_conn: &mut Self::Connection) -> Result<FixtureSnapshot<Self>, Error> {\n        // TODO: I want to get the testing feature out the door so this will have to wait,\n        // but I'm keeping the code around for now because I plan to come back to it.\n        todo!()\n    }\n}\n\nasync fn test_context(args: &TestArgs) -> Result<TestContext<Postgres>, Error> {\n    let url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n\n    let master_opts = PgConnectOptions::from_str(&url).expect(\"failed to parse DATABASE_URL\");\n\n    let pool = PoolOptions::new()\n        // Postgres' normal connection limit is 100 plus 3 superuser connections\n        // We don't want to use the whole cap and there may be fuzziness here due to\n        // concurrently running tests anyway.\n        .max_connections(20)\n        // Immediately close master connections. Tokio's I/O streams don't like hopping runtimes.\n        .after_release(|_conn, _| Box::pin(async move { Ok(false) }))\n        .connect_lazy_with(master_opts);\n\n    let master_pool = match once_lock_try_insert_polyfill(&MASTER_POOL, pool) {\n        Ok(inserted) => inserted,\n        Err((existing, pool)) => {\n            // Sanity checks.\n            assert_eq!(\n                existing.connect_options().host,\n                pool.connect_options().host,\n                \"DATABASE_URL changed at runtime, host differs\"\n            );\n\n            assert_eq!(\n                existing.connect_options().database,\n                pool.connect_options().database,\n                \"DATABASE_URL changed at runtime, database differs\"\n            );\n\n            existing\n        }\n    };\n\n    let mut conn = master_pool.acquire().await?;\n\n    // language=PostgreSQL\n    conn.execute(\n        // Explicit lock avoids this latent bug: https://stackoverflow.com/a/29908840\n        // I couldn't find a bug on the mailing list for `CREATE SCHEMA` specifically,\n        // but a clearly related bug with `CREATE TABLE` has been known since 2007:\n        // https://www.postgresql.org/message-id/200710222037.l9MKbCJZ098744%40wwwmaster.postgresql.org\n        // magic constant 8318549251334697844 is just 8 ascii bytes 'sqlxtest'.\n        r#\"\n        select pg_advisory_xact_lock(8318549251334697844);\n\n        create schema if not exists _sqlx_test;\n\n        create table if not exists _sqlx_test.databases (\n            db_name text primary key,\n            test_path text not null,\n            created_at timestamptz not null default now()\n        );\n\n        create index if not exists databases_created_at \n            on _sqlx_test.databases(created_at);\n\n        create sequence if not exists _sqlx_test.database_ids;\n    \"#,\n    )\n    .await?;\n\n    let db_name = Postgres::db_name(args);\n    do_cleanup(&mut conn, &db_name).await?;\n\n    query(\n        r#\"\n            insert into _sqlx_test.databases(db_name, test_path) values ($1, $2)\n        \"#,\n    )\n    .bind(&db_name)\n    .bind(args.test_path)\n    .execute(&mut *conn)\n    .await?;\n\n    let create_command = format!(\"create database {db_name:?}\");\n    debug_assert!(create_command.starts_with(\"create database \\\"\"));\n    conn.execute(AssertSqlSafe(create_command)).await?;\n\n    Ok(TestContext {\n        pool_opts: PoolOptions::new()\n            // Don't allow a single test to take all the connections.\n            // Most tests shouldn't require more than 5 connections concurrently,\n            // or else they're likely doing too much in one test.\n            .max_connections(5)\n            // Close connections ASAP if left in the idle queue.\n            .idle_timeout(Some(Duration::from_secs(1)))\n            .parent(master_pool.clone()),\n        connect_opts: master_pool\n            .connect_options()\n            .deref()\n            .clone()\n            .database(&db_name),\n        db_name,\n    })\n}\n\nasync fn do_cleanup(conn: &mut PgConnection, db_name: &str) -> Result<(), Error> {\n    let delete_db_command = format!(\"drop database if exists {db_name:?};\");\n    conn.execute(AssertSqlSafe(delete_db_command)).await?;\n    query(\"delete from _sqlx_test.databases where db_name = $1::text\")\n        .bind(db_name)\n        .execute(&mut *conn)\n        .await?;\n\n    Ok(())\n}\n\nfn once_lock_try_insert_polyfill<T>(this: &OnceLock<T>, value: T) -> Result<&T, (&T, T)> {\n    let mut value = Some(value);\n    let res = this.get_or_init(|| value.take().unwrap());\n    match value {\n        None => Ok(res),\n        Some(value) => Err((res, value)),\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/transaction.rs",
    "content": "use sqlx_core::database::Database;\nuse sqlx_core::sql_str::SqlStr;\n\nuse crate::error::Error;\nuse crate::executor::Executor;\n\nuse crate::{PgConnection, Postgres};\n\npub(crate) use sqlx_core::transaction::*;\n\n/// Implementation of [`TransactionManager`] for PostgreSQL.\npub struct PgTransactionManager;\n\nimpl TransactionManager for PgTransactionManager {\n    type Database = Postgres;\n\n    async fn begin(conn: &mut PgConnection, statement: Option<SqlStr>) -> Result<(), Error> {\n        let depth = conn.inner.transaction_depth;\n\n        let statement = match statement {\n            // custom `BEGIN` statements are not allowed if we're already in\n            // a transaction (we need to issue a `SAVEPOINT` instead)\n            Some(_) if depth > 0 => return Err(Error::InvalidSavePointStatement),\n            Some(statement) => statement,\n            None => begin_ansi_transaction_sql(depth),\n        };\n\n        let rollback = Rollback::new(conn);\n        rollback.conn.queue_simple_query(statement.as_str())?;\n        rollback.conn.wait_until_ready().await?;\n        if !rollback.conn.in_transaction() {\n            return Err(Error::BeginFailed);\n        }\n        rollback.conn.inner.transaction_depth += 1;\n        rollback.defuse();\n\n        Ok(())\n    }\n\n    async fn commit(conn: &mut PgConnection) -> Result<(), Error> {\n        if conn.inner.transaction_depth > 0 {\n            conn.execute(commit_ansi_transaction_sql(conn.inner.transaction_depth))\n                .await?;\n\n            conn.inner.transaction_depth -= 1;\n        }\n\n        Ok(())\n    }\n\n    async fn rollback(conn: &mut PgConnection) -> Result<(), Error> {\n        if conn.inner.transaction_depth > 0 {\n            conn.execute(rollback_ansi_transaction_sql(conn.inner.transaction_depth))\n                .await?;\n\n            conn.inner.transaction_depth -= 1;\n        }\n\n        Ok(())\n    }\n\n    fn start_rollback(conn: &mut PgConnection) {\n        if conn.inner.transaction_depth > 0 {\n            conn.queue_simple_query(\n                rollback_ansi_transaction_sql(conn.inner.transaction_depth).as_str(),\n            )\n            .expect(\"BUG: Rollback query somehow too large for protocol\");\n\n            conn.inner.transaction_depth -= 1;\n        }\n    }\n\n    fn get_transaction_depth(conn: &<Self::Database as Database>::Connection) -> usize {\n        conn.inner.transaction_depth\n    }\n}\n\nstruct Rollback<'c> {\n    conn: &'c mut PgConnection,\n    defuse: bool,\n}\n\nimpl Drop for Rollback<'_> {\n    fn drop(&mut self) {\n        if !self.defuse {\n            PgTransactionManager::start_rollback(self.conn)\n        }\n    }\n}\n\nimpl<'c> Rollback<'c> {\n    fn new(conn: &'c mut PgConnection) -> Self {\n        Self {\n            conn,\n            defuse: false,\n        }\n    }\n    fn defuse(mut self) {\n        self.defuse = true;\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/type_checking.rs",
    "content": "use crate::Postgres;\n\n// The paths used below will also be emitted by the macros so they have to match the final facade.\n#[allow(unused_imports, dead_code)]\nmod sqlx {\n    pub use crate as postgres;\n    pub use sqlx_core::*;\n}\n\nimpl_type_checking!(\n        Postgres {\n        (),\n        bool,\n        String | &str,\n        i8,\n        i16,\n        i32,\n        i64,\n        f32,\n        f64,\n        Vec<u8> | &[u8],\n\n        sqlx::postgres::types::Oid,\n\n        sqlx::postgres::types::PgInterval,\n\n        sqlx::postgres::types::PgMoney,\n\n        sqlx::postgres::types::PgLTree,\n\n        sqlx::postgres::types::PgLQuery,\n\n        sqlx::postgres::types::PgCube,\n\n        sqlx::postgres::types::PgPoint,\n\n        sqlx::postgres::types::PgLine,\n\n        sqlx::postgres::types::PgLSeg,\n\n        sqlx::postgres::types::PgBox,\n\n        sqlx::postgres::types::PgPath,\n\n        sqlx::postgres::types::PgPolygon,\n\n        sqlx::postgres::types::PgCircle,\n\n        #[cfg(feature = \"uuid\")]\n        sqlx::types::Uuid,\n\n        #[cfg(feature = \"ipnetwork\")]\n        sqlx::types::ipnetwork::IpNetwork,\n\n        #[cfg(feature = \"ipnet\")]\n        sqlx::types::ipnet::IpNet,\n\n        #[cfg(feature = \"mac_address\")]\n        sqlx::types::mac_address::MacAddress,\n\n        #[cfg(feature = \"json\")]\n        sqlx::types::JsonValue,\n\n        #[cfg(feature = \"bit-vec\")]\n        sqlx::types::BitVec,\n\n        sqlx::postgres::types::PgHstore,\n        // Arrays\n\n        Vec<bool> | &[bool],\n        Vec<String> | &[String],\n        Vec<Vec<u8>> | &[Vec<u8>],\n        Vec<i8> | &[i8],\n        Vec<i16> | &[i16],\n        Vec<i32> | &[i32],\n        Vec<i64> | &[i64],\n        Vec<f32> | &[f32],\n        Vec<f64> | &[f64],\n        Vec<sqlx::postgres::types::Oid> | &[sqlx::postgres::types::Oid],\n        Vec<sqlx::postgres::types::PgMoney> | &[sqlx::postgres::types::PgMoney],\n        Vec<sqlx::postgres::types::PgInterval> | &[sqlx::postgres::types::PgInterval],\n\n        #[cfg(feature = \"uuid\")]\n        Vec<sqlx::types::Uuid> | &[sqlx::types::Uuid],\n\n        #[cfg(feature = \"ipnetwork\")]\n        Vec<sqlx::types::ipnetwork::IpNetwork> | &[sqlx::types::ipnetwork::IpNetwork],\n\n        #[cfg(feature = \"ipnet\")]\n        Vec<sqlx::types::ipnet::IpNet> | &[sqlx::types::ipnet::IpNet],\n\n        #[cfg(feature = \"mac_address\")]\n        Vec<sqlx::types::mac_address::MacAddress> | &[sqlx::types::mac_address::MacAddress],\n\n        #[cfg(feature = \"json\")]\n        Vec<sqlx::types::JsonValue> | &[sqlx::types::JsonValue],\n\n        Vec<sqlx::postgres::types::PgHstore> | &[sqlx::postgres::types::PgHstore],\n\n        // Ranges\n\n        sqlx::postgres::types::PgRange<i32>,\n        sqlx::postgres::types::PgRange<i64>,\n\n        // Range arrays\n\n        Vec<sqlx::postgres::types::PgRange<i32>> | &[sqlx::postgres::types::PgRange<i32>],\n        Vec<sqlx::postgres::types::PgRange<i64>> | &[sqlx::postgres::types::PgRange<i64>],\n    },\n    ParamChecking::Strong,\n    feature-types: info => info.__type_feature_gate(),\n    // The expansion of the macro automatically applies the correct feature name\n    // and checks `[macros.preferred-crates]`\n    datetime-types: {\n        chrono: {\n            // Scalar types\n            sqlx::types::chrono::NaiveTime,\n\n            sqlx::types::chrono::NaiveDate,\n\n            sqlx::types::chrono::NaiveDateTime,\n\n            sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc> | sqlx::types::chrono::DateTime<_>,\n\n            sqlx::postgres::types::PgTimeTz<sqlx::types::chrono::NaiveTime, sqlx::types::chrono::FixedOffset>,\n\n            // Array types\n            Vec<sqlx::types::chrono::NaiveTime> | &[sqlx::types::chrono::NaiveTime],\n\n            Vec<sqlx::types::chrono::NaiveDate> | &[sqlx::types::chrono::NaiveDate],\n\n            Vec<sqlx::types::chrono::NaiveDateTime> | &[sqlx::types::chrono::NaiveDateTime],\n\n            Vec<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>> | &[sqlx::types::chrono::DateTime<_>],\n\n            // Range types\n            sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>,\n\n            sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>,\n\n            sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>> |\n                sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>,\n\n            // Arrays of ranges\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDate>],\n\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::chrono::NaiveDateTime>],\n\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::chrono::DateTime<_>>],\n        },\n        time: {\n            // Scalar types\n            sqlx::types::time::Time,\n\n            sqlx::types::time::Date,\n\n            sqlx::types::time::PrimitiveDateTime,\n\n            sqlx::types::time::OffsetDateTime,\n\n            sqlx::postgres::types::PgTimeTz<sqlx::types::time::Time, sqlx::types::time::UtcOffset>,\n\n            // Array types\n            Vec<sqlx::types::time::Time> | &[sqlx::types::time::Time],\n\n            Vec<sqlx::types::time::Date> | &[sqlx::types::time::Date],\n\n            Vec<sqlx::types::time::PrimitiveDateTime> | &[sqlx::types::time::PrimitiveDateTime],\n\n            Vec<sqlx::types::time::OffsetDateTime> | &[sqlx::types::time::OffsetDateTime],\n\n            // Range types\n            sqlx::postgres::types::PgRange<sqlx::types::time::Date>,\n\n            sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>,\n\n            sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>,\n\n            // Arrays of ranges\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::time::Date>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::time::Date>],\n\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::time::PrimitiveDateTime>],\n\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::time::OffsetDateTime>],\n        },\n    },\n    numeric-types: {\n        bigdecimal: {\n            sqlx::types::BigDecimal,\n\n            Vec<sqlx::types::BigDecimal> | &[sqlx::types::BigDecimal],\n\n            sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>,\n\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::BigDecimal>],\n        },\n        rust_decimal: {\n            sqlx::types::Decimal,\n\n            Vec<sqlx::types::Decimal> | &[sqlx::types::Decimal],\n\n            sqlx::postgres::types::PgRange<sqlx::types::Decimal>,\n\n            Vec<sqlx::postgres::types::PgRange<sqlx::types::Decimal>> |\n                &[sqlx::postgres::types::PgRange<sqlx::types::Decimal>],\n        },\n    },\n);\n"
  },
  {
    "path": "sqlx-postgres/src/type_info.rs",
    "content": "#![allow(dead_code)]\n\nuse std::borrow::Cow;\nuse std::fmt::{self, Display, Formatter};\nuse std::ops::Deref;\nuse std::sync::Arc;\n\nuse crate::ext::ustr::UStr;\nuse crate::types::Oid;\n\npub(crate) use sqlx_core::type_info::TypeInfo;\n\n/// Type information for a PostgreSQL type.\n///\n/// ### Note: Implementation of `==` ([`PartialEq::eq()`])\n/// Because `==` on [`TypeInfo`]s has been used throughout the SQLx API as a synonym for type compatibility,\n/// e.g. in the default impl of [`Type::compatible()`][sqlx_core::types::Type::compatible],\n/// some concessions have been made in the implementation.\n///\n/// When comparing two `PgTypeInfo`s using the `==` operator ([`PartialEq::eq()`]),\n/// if one was constructed with [`Self::with_oid()`] and the other with [`Self::with_name()`] or\n/// [`Self::array_of()`], `==` will return `true`:\n///\n/// ```\n/// # use sqlx::postgres::{types::Oid, PgTypeInfo};\n/// // Potentially surprising result, this assert will pass:\n/// assert_eq!(PgTypeInfo::with_oid(Oid(1)), PgTypeInfo::with_name(\"definitely_not_real\"));\n/// ```\n///\n/// Since it is not possible in this case to prove the types are _not_ compatible (because\n/// both `PgTypeInfo`s need to be resolved by an active connection to know for sure)\n/// and type compatibility is mainly done as a sanity check anyway,\n/// it was deemed acceptable to fudge equality in this very specific case.\n///\n/// This also applies when querying with the text protocol (not using prepared statements,\n/// e.g. [`sqlx::raw_sql()`][sqlx_core::raw_sql::raw_sql]), as the connection will be unable\n/// to look up the type info like it normally does when preparing a statement: it won't know\n/// what the OIDs of the output columns will be until it's in the middle of reading the result,\n/// and by that time it's too late.\n///\n/// To compare types for exact equality, use [`Self::type_eq()`] instead.\n#[derive(Debug, Clone, PartialEq)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct PgTypeInfo(pub(crate) PgType);\n\nimpl Deref for PgTypeInfo {\n    type Target = PgType;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\n#[repr(u32)]\npub enum PgType {\n    Bool,\n    Bytea,\n    Char,\n    Name,\n    Int8,\n    Int2,\n    Int4,\n    Text,\n    Oid,\n    Json,\n    JsonArray,\n    Point,\n    Lseg,\n    Path,\n    Box,\n    Polygon,\n    Line,\n    LineArray,\n    Cidr,\n    CidrArray,\n    Float4,\n    Float8,\n    Unknown,\n    Circle,\n    CircleArray,\n    Macaddr8,\n    Macaddr8Array,\n    Macaddr,\n    Inet,\n    BoolArray,\n    ByteaArray,\n    CharArray,\n    NameArray,\n    Int2Array,\n    Int4Array,\n    TextArray,\n    BpcharArray,\n    VarcharArray,\n    Int8Array,\n    PointArray,\n    LsegArray,\n    PathArray,\n    BoxArray,\n    Float4Array,\n    Float8Array,\n    PolygonArray,\n    OidArray,\n    MacaddrArray,\n    InetArray,\n    Bpchar,\n    Varchar,\n    Date,\n    Time,\n    Timestamp,\n    TimestampArray,\n    DateArray,\n    TimeArray,\n    Timestamptz,\n    TimestamptzArray,\n    Interval,\n    IntervalArray,\n    NumericArray,\n    Timetz,\n    TimetzArray,\n    Bit,\n    BitArray,\n    Varbit,\n    VarbitArray,\n    Numeric,\n    Record,\n    RecordArray,\n    Uuid,\n    UuidArray,\n    Jsonb,\n    JsonbArray,\n    Int4Range,\n    Int4RangeArray,\n    NumRange,\n    NumRangeArray,\n    TsRange,\n    TsRangeArray,\n    TstzRange,\n    TstzRangeArray,\n    DateRange,\n    DateRangeArray,\n    Int8Range,\n    Int8RangeArray,\n    Jsonpath,\n    JsonpathArray,\n    Money,\n    MoneyArray,\n\n    // https://www.postgresql.org/docs/9.3/datatype-pseudo.html\n    Void,\n\n    // A realized user-defined type. When a connection sees a DeclareXX variant it resolves\n    // into this one before passing it along to `accepts` or inside of `Value` objects.\n    Custom(Arc<PgCustomType>),\n\n    // From [`PgTypeInfo::with_name`]\n    DeclareWithName(UStr),\n\n    // NOTE: Do we want to bring back type declaration by ID? It's notoriously fragile but\n    //       someone may have a user for it\n    DeclareWithOid(Oid),\n\n    DeclareArrayOf(Arc<PgArrayOf>),\n}\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct PgCustomType {\n    #[cfg_attr(feature = \"offline\", serde(skip))]\n    pub(crate) oid: Oid,\n    pub(crate) name: UStr,\n    pub(crate) kind: PgTypeKind,\n}\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub enum PgTypeKind {\n    Simple,\n    Pseudo,\n    Domain(PgTypeInfo),\n    Composite(Arc<[(String, PgTypeInfo)]>),\n    Array(PgTypeInfo),\n    Enum(Arc<[String]>),\n    Range(PgTypeInfo),\n}\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct PgArrayOf {\n    pub(crate) elem_name: UStr,\n    pub(crate) name: Box<str>,\n}\n\nimpl PgTypeInfo {\n    /// Returns the corresponding `PgTypeInfo` if the OID is a built-in type and recognized by SQLx.\n    pub(crate) fn try_from_oid(oid: Oid) -> Option<Self> {\n        PgType::try_from_oid(oid).map(Self)\n    }\n\n    /// Returns the _kind_ (simple, array, enum, etc.) for this type.\n    pub fn kind(&self) -> &PgTypeKind {\n        self.0.kind()\n    }\n\n    /// Returns the OID for this type, if available.\n    ///\n    /// The OID may not be available if SQLx only knows the type by name.\n    /// It will have to be resolved by a `PgConnection` at runtime which\n    /// will yield a new and semantically distinct `TypeInfo` instance.\n    ///\n    /// This method does not perform any such lookup.\n    ///\n    /// ### Note\n    /// With the exception of [the default `pg_type` catalog][pg_type], type OIDs are *not* stable in PostgreSQL.\n    /// If a type is added by an extension, its OID will be assigned when the `CREATE EXTENSION` statement is executed,\n    /// and so can change depending on what extensions are installed and in what order, as well as the exact\n    /// version of PostgreSQL.\n    ///\n    /// [pg_type]: https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat\n    pub fn oid(&self) -> Option<Oid> {\n        self.0.try_oid()\n    }\n\n    #[doc(hidden)]\n    pub fn __type_feature_gate(&self) -> Option<&'static str> {\n        if [\n            PgTypeInfo::DATE,\n            PgTypeInfo::TIME,\n            PgTypeInfo::TIMESTAMP,\n            PgTypeInfo::TIMESTAMPTZ,\n            PgTypeInfo::DATE_ARRAY,\n            PgTypeInfo::TIME_ARRAY,\n            PgTypeInfo::TIMESTAMP_ARRAY,\n            PgTypeInfo::TIMESTAMPTZ_ARRAY,\n        ]\n        .contains(self)\n        {\n            Some(\"time\")\n        } else if [PgTypeInfo::UUID, PgTypeInfo::UUID_ARRAY].contains(self) {\n            Some(\"uuid\")\n        } else if [\n            PgTypeInfo::JSON,\n            PgTypeInfo::JSONB,\n            PgTypeInfo::JSON_ARRAY,\n            PgTypeInfo::JSONB_ARRAY,\n        ]\n        .contains(self)\n        {\n            Some(\"json\")\n        } else if [\n            PgTypeInfo::CIDR,\n            PgTypeInfo::INET,\n            PgTypeInfo::CIDR_ARRAY,\n            PgTypeInfo::INET_ARRAY,\n        ]\n        .contains(self)\n        {\n            Some(\"ipnetwork\")\n        } else if [PgTypeInfo::MACADDR].contains(self) {\n            Some(\"mac_address\")\n        } else if [PgTypeInfo::NUMERIC, PgTypeInfo::NUMERIC_ARRAY].contains(self) {\n            Some(\"bigdecimal\")\n        } else {\n            None\n        }\n    }\n\n    /// Create a `PgTypeInfo` from a type name.\n    ///\n    /// The OID for the type will be fetched from Postgres on use of\n    /// a value of this type. The fetched OID will be cached per-connection.\n    ///\n    /// ### Note: Type Names Prefixed with `_`\n    /// In `pg_catalog.pg_type`, Postgres prefixes a type name with `_` to denote an array of that\n    /// type, e.g. `int4[]` actually exists in `pg_type` as `_int4`.\n    ///\n    /// Previously, it was necessary in manual [`PgHasArrayType`][crate::PgHasArrayType] impls\n    /// to return [`PgTypeInfo::with_name()`] with the type name prefixed with `_` to denote\n    /// an array type, but this would not work with schema-qualified names.\n    ///\n    /// As of 0.8, [`PgTypeInfo::array_of()`] is used to declare an array type,\n    /// and the Postgres driver is now able to properly resolve arrays of custom types,\n    /// even in other schemas, which was not previously supported.\n    ///\n    /// It is highly recommended to migrate existing usages to [`PgTypeInfo::array_of()`] where\n    /// applicable.\n    ///\n    /// However, to maintain compatibility, the driver now infers any type name prefixed with `_`\n    /// to be an array of that type. This may introduce some breakages for types which use\n    /// a `_` prefix but which are not arrays.\n    ///\n    /// As a workaround, type names with `_` as a prefix but which are not arrays should be wrapped\n    /// in quotes, e.g.:\n    /// ```\n    /// use sqlx::postgres::PgTypeInfo;\n    /// use sqlx::{Type, TypeInfo};\n    ///\n    /// /// `CREATE TYPE \"_foo\" AS ENUM ('Bar', 'Baz');`\n    /// #[derive(sqlx::Type)]\n    /// // Will prevent SQLx from inferring `_foo` as an array type.\n    /// #[sqlx(type_name = r#\"\"_foo\"\"#)]\n    /// enum Foo {\n    ///     Bar,\n    ///     Baz\n    /// }\n    ///\n    /// assert_eq!(Foo::type_info().name(), r#\"\"_foo\"\"#);\n    /// ```\n    pub const fn with_name(name: &'static str) -> Self {\n        Self(PgType::DeclareWithName(UStr::Static(name)))\n    }\n\n    /// Create a `PgTypeInfo` of an array from the name of its element type.\n    ///\n    /// The array type OID will be fetched from Postgres on use of a value of this type.\n    /// The fetched OID will be cached per-connection.\n    pub fn array_of(elem_name: &'static str) -> Self {\n        // to satisfy `name()` and `display_name()`, we need to construct strings to return\n        Self(PgType::DeclareArrayOf(Arc::new(PgArrayOf {\n            elem_name: elem_name.into(),\n            name: format!(\"{elem_name}[]\").into(),\n        })))\n    }\n\n    /// Create a `PgTypeInfo` from an OID.\n    ///\n    /// Note that the OID for a type is very dependent on the environment. If you only ever use\n    /// one database or if this is an unhandled built-in type, you should be fine. Otherwise,\n    /// you will be better served using [`Self::with_name()`].\n    ///\n    /// ### Note: Interaction with `==`\n    /// This constructor may give surprising results with `==`.\n    ///\n    /// See [the type-level docs][Self] for details.\n    pub const fn with_oid(oid: Oid) -> Self {\n        Self(PgType::DeclareWithOid(oid))\n    }\n\n    /// Returns `true` if `self` can be compared exactly to `other`.\n    ///\n    /// Unlike `==`, this will return false if\n    pub fn type_eq(&self, other: &Self) -> bool {\n        self.eq_impl(other, false)\n    }\n}\n\n// DEVELOPER PRO TIP: find builtin type OIDs easily by grepping this file\n// https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat\n//\n// If you have Postgres running locally you can also try\n// SELECT oid, typarray FROM pg_type where typname = '<type name>'\n\nimpl PgType {\n    /// Returns the corresponding `PgType` if the OID is a built-in type and recognized by SQLx.\n    pub(crate) fn try_from_oid(oid: Oid) -> Option<Self> {\n        Some(match oid.0 {\n            16 => PgType::Bool,\n            17 => PgType::Bytea,\n            18 => PgType::Char,\n            19 => PgType::Name,\n            20 => PgType::Int8,\n            21 => PgType::Int2,\n            23 => PgType::Int4,\n            25 => PgType::Text,\n            26 => PgType::Oid,\n            114 => PgType::Json,\n            199 => PgType::JsonArray,\n            600 => PgType::Point,\n            601 => PgType::Lseg,\n            602 => PgType::Path,\n            603 => PgType::Box,\n            604 => PgType::Polygon,\n            628 => PgType::Line,\n            629 => PgType::LineArray,\n            650 => PgType::Cidr,\n            651 => PgType::CidrArray,\n            700 => PgType::Float4,\n            701 => PgType::Float8,\n            705 => PgType::Unknown,\n            718 => PgType::Circle,\n            719 => PgType::CircleArray,\n            774 => PgType::Macaddr8,\n            775 => PgType::Macaddr8Array,\n            790 => PgType::Money,\n            791 => PgType::MoneyArray,\n            829 => PgType::Macaddr,\n            869 => PgType::Inet,\n            1000 => PgType::BoolArray,\n            1001 => PgType::ByteaArray,\n            1002 => PgType::CharArray,\n            1003 => PgType::NameArray,\n            1005 => PgType::Int2Array,\n            1007 => PgType::Int4Array,\n            1009 => PgType::TextArray,\n            1014 => PgType::BpcharArray,\n            1015 => PgType::VarcharArray,\n            1016 => PgType::Int8Array,\n            1017 => PgType::PointArray,\n            1018 => PgType::LsegArray,\n            1019 => PgType::PathArray,\n            1020 => PgType::BoxArray,\n            1021 => PgType::Float4Array,\n            1022 => PgType::Float8Array,\n            1027 => PgType::PolygonArray,\n            1028 => PgType::OidArray,\n            1040 => PgType::MacaddrArray,\n            1041 => PgType::InetArray,\n            1042 => PgType::Bpchar,\n            1043 => PgType::Varchar,\n            1082 => PgType::Date,\n            1083 => PgType::Time,\n            1114 => PgType::Timestamp,\n            1115 => PgType::TimestampArray,\n            1182 => PgType::DateArray,\n            1183 => PgType::TimeArray,\n            1184 => PgType::Timestamptz,\n            1185 => PgType::TimestamptzArray,\n            1186 => PgType::Interval,\n            1187 => PgType::IntervalArray,\n            1231 => PgType::NumericArray,\n            1266 => PgType::Timetz,\n            1270 => PgType::TimetzArray,\n            1560 => PgType::Bit,\n            1561 => PgType::BitArray,\n            1562 => PgType::Varbit,\n            1563 => PgType::VarbitArray,\n            1700 => PgType::Numeric,\n            2278 => PgType::Void,\n            2249 => PgType::Record,\n            2287 => PgType::RecordArray,\n            2950 => PgType::Uuid,\n            2951 => PgType::UuidArray,\n            3802 => PgType::Jsonb,\n            3807 => PgType::JsonbArray,\n            3904 => PgType::Int4Range,\n            3905 => PgType::Int4RangeArray,\n            3906 => PgType::NumRange,\n            3907 => PgType::NumRangeArray,\n            3908 => PgType::TsRange,\n            3909 => PgType::TsRangeArray,\n            3910 => PgType::TstzRange,\n            3911 => PgType::TstzRangeArray,\n            3912 => PgType::DateRange,\n            3913 => PgType::DateRangeArray,\n            3926 => PgType::Int8Range,\n            3927 => PgType::Int8RangeArray,\n            4072 => PgType::Jsonpath,\n            4073 => PgType::JsonpathArray,\n\n            _ => {\n                return None;\n            }\n        })\n    }\n\n    pub(crate) fn oid(&self) -> Oid {\n        match self.try_oid() {\n            Some(oid) => oid,\n            None => unreachable!(\"(bug) use of unresolved type declaration [oid]\"),\n        }\n    }\n\n    pub(crate) fn try_oid(&self) -> Option<Oid> {\n        Some(match self {\n            PgType::Bool => Oid(16),\n            PgType::Bytea => Oid(17),\n            PgType::Char => Oid(18),\n            PgType::Name => Oid(19),\n            PgType::Int8 => Oid(20),\n            PgType::Int2 => Oid(21),\n            PgType::Int4 => Oid(23),\n            PgType::Text => Oid(25),\n            PgType::Oid => Oid(26),\n            PgType::Json => Oid(114),\n            PgType::JsonArray => Oid(199),\n            PgType::Point => Oid(600),\n            PgType::Lseg => Oid(601),\n            PgType::Path => Oid(602),\n            PgType::Box => Oid(603),\n            PgType::Polygon => Oid(604),\n            PgType::Line => Oid(628),\n            PgType::LineArray => Oid(629),\n            PgType::Cidr => Oid(650),\n            PgType::CidrArray => Oid(651),\n            PgType::Float4 => Oid(700),\n            PgType::Float8 => Oid(701),\n            PgType::Unknown => Oid(705),\n            PgType::Circle => Oid(718),\n            PgType::CircleArray => Oid(719),\n            PgType::Macaddr8 => Oid(774),\n            PgType::Macaddr8Array => Oid(775),\n            PgType::Money => Oid(790),\n            PgType::MoneyArray => Oid(791),\n            PgType::Macaddr => Oid(829),\n            PgType::Inet => Oid(869),\n            PgType::BoolArray => Oid(1000),\n            PgType::ByteaArray => Oid(1001),\n            PgType::CharArray => Oid(1002),\n            PgType::NameArray => Oid(1003),\n            PgType::Int2Array => Oid(1005),\n            PgType::Int4Array => Oid(1007),\n            PgType::TextArray => Oid(1009),\n            PgType::BpcharArray => Oid(1014),\n            PgType::VarcharArray => Oid(1015),\n            PgType::Int8Array => Oid(1016),\n            PgType::PointArray => Oid(1017),\n            PgType::LsegArray => Oid(1018),\n            PgType::PathArray => Oid(1019),\n            PgType::BoxArray => Oid(1020),\n            PgType::Float4Array => Oid(1021),\n            PgType::Float8Array => Oid(1022),\n            PgType::PolygonArray => Oid(1027),\n            PgType::OidArray => Oid(1028),\n            PgType::MacaddrArray => Oid(1040),\n            PgType::InetArray => Oid(1041),\n            PgType::Bpchar => Oid(1042),\n            PgType::Varchar => Oid(1043),\n            PgType::Date => Oid(1082),\n            PgType::Time => Oid(1083),\n            PgType::Timestamp => Oid(1114),\n            PgType::TimestampArray => Oid(1115),\n            PgType::DateArray => Oid(1182),\n            PgType::TimeArray => Oid(1183),\n            PgType::Timestamptz => Oid(1184),\n            PgType::TimestamptzArray => Oid(1185),\n            PgType::Interval => Oid(1186),\n            PgType::IntervalArray => Oid(1187),\n            PgType::NumericArray => Oid(1231),\n            PgType::Timetz => Oid(1266),\n            PgType::TimetzArray => Oid(1270),\n            PgType::Bit => Oid(1560),\n            PgType::BitArray => Oid(1561),\n            PgType::Varbit => Oid(1562),\n            PgType::VarbitArray => Oid(1563),\n            PgType::Numeric => Oid(1700),\n            PgType::Void => Oid(2278),\n            PgType::Record => Oid(2249),\n            PgType::RecordArray => Oid(2287),\n            PgType::Uuid => Oid(2950),\n            PgType::UuidArray => Oid(2951),\n            PgType::Jsonb => Oid(3802),\n            PgType::JsonbArray => Oid(3807),\n            PgType::Int4Range => Oid(3904),\n            PgType::Int4RangeArray => Oid(3905),\n            PgType::NumRange => Oid(3906),\n            PgType::NumRangeArray => Oid(3907),\n            PgType::TsRange => Oid(3908),\n            PgType::TsRangeArray => Oid(3909),\n            PgType::TstzRange => Oid(3910),\n            PgType::TstzRangeArray => Oid(3911),\n            PgType::DateRange => Oid(3912),\n            PgType::DateRangeArray => Oid(3913),\n            PgType::Int8Range => Oid(3926),\n            PgType::Int8RangeArray => Oid(3927),\n            PgType::Jsonpath => Oid(4072),\n            PgType::JsonpathArray => Oid(4073),\n\n            PgType::Custom(ty) => ty.oid,\n\n            PgType::DeclareWithOid(oid) => *oid,\n            PgType::DeclareWithName(_) => {\n                return None;\n            }\n            PgType::DeclareArrayOf(_) => {\n                return None;\n            }\n        })\n    }\n\n    pub(crate) fn display_name(&self) -> &str {\n        match self {\n            PgType::Bool => \"BOOL\",\n            PgType::Bytea => \"BYTEA\",\n            PgType::Char => \"\\\"CHAR\\\"\",\n            PgType::Name => \"NAME\",\n            PgType::Int8 => \"INT8\",\n            PgType::Int2 => \"INT2\",\n            PgType::Int4 => \"INT4\",\n            PgType::Text => \"TEXT\",\n            PgType::Oid => \"OID\",\n            PgType::Json => \"JSON\",\n            PgType::JsonArray => \"JSON[]\",\n            PgType::Point => \"POINT\",\n            PgType::Lseg => \"LSEG\",\n            PgType::Path => \"PATH\",\n            PgType::Box => \"BOX\",\n            PgType::Polygon => \"POLYGON\",\n            PgType::Line => \"LINE\",\n            PgType::LineArray => \"LINE[]\",\n            PgType::Cidr => \"CIDR\",\n            PgType::CidrArray => \"CIDR[]\",\n            PgType::Float4 => \"FLOAT4\",\n            PgType::Float8 => \"FLOAT8\",\n            PgType::Unknown => \"UNKNOWN\",\n            PgType::Circle => \"CIRCLE\",\n            PgType::CircleArray => \"CIRCLE[]\",\n            PgType::Macaddr8 => \"MACADDR8\",\n            PgType::Macaddr8Array => \"MACADDR8[]\",\n            PgType::Macaddr => \"MACADDR\",\n            PgType::Inet => \"INET\",\n            PgType::BoolArray => \"BOOL[]\",\n            PgType::ByteaArray => \"BYTEA[]\",\n            PgType::CharArray => \"\\\"CHAR\\\"[]\",\n            PgType::NameArray => \"NAME[]\",\n            PgType::Int2Array => \"INT2[]\",\n            PgType::Int4Array => \"INT4[]\",\n            PgType::TextArray => \"TEXT[]\",\n            PgType::BpcharArray => \"CHAR[]\",\n            PgType::VarcharArray => \"VARCHAR[]\",\n            PgType::Int8Array => \"INT8[]\",\n            PgType::PointArray => \"POINT[]\",\n            PgType::LsegArray => \"LSEG[]\",\n            PgType::PathArray => \"PATH[]\",\n            PgType::BoxArray => \"BOX[]\",\n            PgType::Float4Array => \"FLOAT4[]\",\n            PgType::Float8Array => \"FLOAT8[]\",\n            PgType::PolygonArray => \"POLYGON[]\",\n            PgType::OidArray => \"OID[]\",\n            PgType::MacaddrArray => \"MACADDR[]\",\n            PgType::InetArray => \"INET[]\",\n            PgType::Bpchar => \"CHAR\",\n            PgType::Varchar => \"VARCHAR\",\n            PgType::Date => \"DATE\",\n            PgType::Time => \"TIME\",\n            PgType::Timestamp => \"TIMESTAMP\",\n            PgType::TimestampArray => \"TIMESTAMP[]\",\n            PgType::DateArray => \"DATE[]\",\n            PgType::TimeArray => \"TIME[]\",\n            PgType::Timestamptz => \"TIMESTAMPTZ\",\n            PgType::TimestamptzArray => \"TIMESTAMPTZ[]\",\n            PgType::Interval => \"INTERVAL\",\n            PgType::IntervalArray => \"INTERVAL[]\",\n            PgType::NumericArray => \"NUMERIC[]\",\n            PgType::Timetz => \"TIMETZ\",\n            PgType::TimetzArray => \"TIMETZ[]\",\n            PgType::Bit => \"BIT\",\n            PgType::BitArray => \"BIT[]\",\n            PgType::Varbit => \"VARBIT\",\n            PgType::VarbitArray => \"VARBIT[]\",\n            PgType::Numeric => \"NUMERIC\",\n            PgType::Record => \"RECORD\",\n            PgType::RecordArray => \"RECORD[]\",\n            PgType::Uuid => \"UUID\",\n            PgType::UuidArray => \"UUID[]\",\n            PgType::Jsonb => \"JSONB\",\n            PgType::JsonbArray => \"JSONB[]\",\n            PgType::Int4Range => \"INT4RANGE\",\n            PgType::Int4RangeArray => \"INT4RANGE[]\",\n            PgType::NumRange => \"NUMRANGE\",\n            PgType::NumRangeArray => \"NUMRANGE[]\",\n            PgType::TsRange => \"TSRANGE\",\n            PgType::TsRangeArray => \"TSRANGE[]\",\n            PgType::TstzRange => \"TSTZRANGE\",\n            PgType::TstzRangeArray => \"TSTZRANGE[]\",\n            PgType::DateRange => \"DATERANGE\",\n            PgType::DateRangeArray => \"DATERANGE[]\",\n            PgType::Int8Range => \"INT8RANGE\",\n            PgType::Int8RangeArray => \"INT8RANGE[]\",\n            PgType::Jsonpath => \"JSONPATH\",\n            PgType::JsonpathArray => \"JSONPATH[]\",\n            PgType::Money => \"MONEY\",\n            PgType::MoneyArray => \"MONEY[]\",\n            PgType::Void => \"VOID\",\n            PgType::Custom(ty) => &ty.name,\n            PgType::DeclareWithOid(_) => \"?\",\n            PgType::DeclareWithName(name) => name,\n            PgType::DeclareArrayOf(array) => &array.name,\n        }\n    }\n\n    pub(crate) fn name(&self) -> &str {\n        match self {\n            PgType::Bool => \"bool\",\n            PgType::Bytea => \"bytea\",\n            PgType::Char => \"char\",\n            PgType::Name => \"name\",\n            PgType::Int8 => \"int8\",\n            PgType::Int2 => \"int2\",\n            PgType::Int4 => \"int4\",\n            PgType::Text => \"text\",\n            PgType::Oid => \"oid\",\n            PgType::Json => \"json\",\n            PgType::JsonArray => \"_json\",\n            PgType::Point => \"point\",\n            PgType::Lseg => \"lseg\",\n            PgType::Path => \"path\",\n            PgType::Box => \"box\",\n            PgType::Polygon => \"polygon\",\n            PgType::Line => \"line\",\n            PgType::LineArray => \"_line\",\n            PgType::Cidr => \"cidr\",\n            PgType::CidrArray => \"_cidr\",\n            PgType::Float4 => \"float4\",\n            PgType::Float8 => \"float8\",\n            PgType::Unknown => \"unknown\",\n            PgType::Circle => \"circle\",\n            PgType::CircleArray => \"_circle\",\n            PgType::Macaddr8 => \"macaddr8\",\n            PgType::Macaddr8Array => \"_macaddr8\",\n            PgType::Macaddr => \"macaddr\",\n            PgType::Inet => \"inet\",\n            PgType::BoolArray => \"_bool\",\n            PgType::ByteaArray => \"_bytea\",\n            PgType::CharArray => \"_char\",\n            PgType::NameArray => \"_name\",\n            PgType::Int2Array => \"_int2\",\n            PgType::Int4Array => \"_int4\",\n            PgType::TextArray => \"_text\",\n            PgType::BpcharArray => \"_bpchar\",\n            PgType::VarcharArray => \"_varchar\",\n            PgType::Int8Array => \"_int8\",\n            PgType::PointArray => \"_point\",\n            PgType::LsegArray => \"_lseg\",\n            PgType::PathArray => \"_path\",\n            PgType::BoxArray => \"_box\",\n            PgType::Float4Array => \"_float4\",\n            PgType::Float8Array => \"_float8\",\n            PgType::PolygonArray => \"_polygon\",\n            PgType::OidArray => \"_oid\",\n            PgType::MacaddrArray => \"_macaddr\",\n            PgType::InetArray => \"_inet\",\n            PgType::Bpchar => \"bpchar\",\n            PgType::Varchar => \"varchar\",\n            PgType::Date => \"date\",\n            PgType::Time => \"time\",\n            PgType::Timestamp => \"timestamp\",\n            PgType::TimestampArray => \"_timestamp\",\n            PgType::DateArray => \"_date\",\n            PgType::TimeArray => \"_time\",\n            PgType::Timestamptz => \"timestamptz\",\n            PgType::TimestamptzArray => \"_timestamptz\",\n            PgType::Interval => \"interval\",\n            PgType::IntervalArray => \"_interval\",\n            PgType::NumericArray => \"_numeric\",\n            PgType::Timetz => \"timetz\",\n            PgType::TimetzArray => \"_timetz\",\n            PgType::Bit => \"bit\",\n            PgType::BitArray => \"_bit\",\n            PgType::Varbit => \"varbit\",\n            PgType::VarbitArray => \"_varbit\",\n            PgType::Numeric => \"numeric\",\n            PgType::Record => \"record\",\n            PgType::RecordArray => \"_record\",\n            PgType::Uuid => \"uuid\",\n            PgType::UuidArray => \"_uuid\",\n            PgType::Jsonb => \"jsonb\",\n            PgType::JsonbArray => \"_jsonb\",\n            PgType::Int4Range => \"int4range\",\n            PgType::Int4RangeArray => \"_int4range\",\n            PgType::NumRange => \"numrange\",\n            PgType::NumRangeArray => \"_numrange\",\n            PgType::TsRange => \"tsrange\",\n            PgType::TsRangeArray => \"_tsrange\",\n            PgType::TstzRange => \"tstzrange\",\n            PgType::TstzRangeArray => \"_tstzrange\",\n            PgType::DateRange => \"daterange\",\n            PgType::DateRangeArray => \"_daterange\",\n            PgType::Int8Range => \"int8range\",\n            PgType::Int8RangeArray => \"_int8range\",\n            PgType::Jsonpath => \"jsonpath\",\n            PgType::JsonpathArray => \"_jsonpath\",\n            PgType::Money => \"money\",\n            PgType::MoneyArray => \"_money\",\n            PgType::Void => \"void\",\n            PgType::Custom(ty) => &ty.name,\n            PgType::DeclareWithOid(_) => \"?\",\n            PgType::DeclareWithName(name) => name,\n            PgType::DeclareArrayOf(array) => &array.name,\n        }\n    }\n\n    pub(crate) fn kind(&self) -> &PgTypeKind {\n        match self {\n            PgType::Bool => &PgTypeKind::Simple,\n            PgType::Bytea => &PgTypeKind::Simple,\n            PgType::Char => &PgTypeKind::Simple,\n            PgType::Name => &PgTypeKind::Simple,\n            PgType::Int8 => &PgTypeKind::Simple,\n            PgType::Int2 => &PgTypeKind::Simple,\n            PgType::Int4 => &PgTypeKind::Simple,\n            PgType::Text => &PgTypeKind::Simple,\n            PgType::Oid => &PgTypeKind::Simple,\n            PgType::Json => &PgTypeKind::Simple,\n            PgType::JsonArray => &PgTypeKind::Array(PgTypeInfo(PgType::Json)),\n            PgType::Point => &PgTypeKind::Simple,\n            PgType::Lseg => &PgTypeKind::Simple,\n            PgType::Path => &PgTypeKind::Simple,\n            PgType::Box => &PgTypeKind::Simple,\n            PgType::Polygon => &PgTypeKind::Simple,\n            PgType::Line => &PgTypeKind::Simple,\n            PgType::LineArray => &PgTypeKind::Array(PgTypeInfo(PgType::Line)),\n            PgType::Cidr => &PgTypeKind::Simple,\n            PgType::CidrArray => &PgTypeKind::Array(PgTypeInfo(PgType::Cidr)),\n            PgType::Float4 => &PgTypeKind::Simple,\n            PgType::Float8 => &PgTypeKind::Simple,\n            PgType::Unknown => &PgTypeKind::Simple,\n            PgType::Circle => &PgTypeKind::Simple,\n            PgType::CircleArray => &PgTypeKind::Array(PgTypeInfo(PgType::Circle)),\n            PgType::Macaddr8 => &PgTypeKind::Simple,\n            PgType::Macaddr8Array => &PgTypeKind::Array(PgTypeInfo(PgType::Macaddr8)),\n            PgType::Macaddr => &PgTypeKind::Simple,\n            PgType::Inet => &PgTypeKind::Simple,\n            PgType::BoolArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bool)),\n            PgType::ByteaArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bytea)),\n            PgType::CharArray => &PgTypeKind::Array(PgTypeInfo(PgType::Char)),\n            PgType::NameArray => &PgTypeKind::Array(PgTypeInfo(PgType::Name)),\n            PgType::Int2Array => &PgTypeKind::Array(PgTypeInfo(PgType::Int2)),\n            PgType::Int4Array => &PgTypeKind::Array(PgTypeInfo(PgType::Int4)),\n            PgType::TextArray => &PgTypeKind::Array(PgTypeInfo(PgType::Text)),\n            PgType::BpcharArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bpchar)),\n            PgType::VarcharArray => &PgTypeKind::Array(PgTypeInfo(PgType::Varchar)),\n            PgType::Int8Array => &PgTypeKind::Array(PgTypeInfo(PgType::Int8)),\n            PgType::PointArray => &PgTypeKind::Array(PgTypeInfo(PgType::Point)),\n            PgType::LsegArray => &PgTypeKind::Array(PgTypeInfo(PgType::Lseg)),\n            PgType::PathArray => &PgTypeKind::Array(PgTypeInfo(PgType::Path)),\n            PgType::BoxArray => &PgTypeKind::Array(PgTypeInfo(PgType::Box)),\n            PgType::Float4Array => &PgTypeKind::Array(PgTypeInfo(PgType::Float4)),\n            PgType::Float8Array => &PgTypeKind::Array(PgTypeInfo(PgType::Float8)),\n            PgType::PolygonArray => &PgTypeKind::Array(PgTypeInfo(PgType::Polygon)),\n            PgType::OidArray => &PgTypeKind::Array(PgTypeInfo(PgType::Oid)),\n            PgType::MacaddrArray => &PgTypeKind::Array(PgTypeInfo(PgType::Macaddr)),\n            PgType::InetArray => &PgTypeKind::Array(PgTypeInfo(PgType::Inet)),\n            PgType::Bpchar => &PgTypeKind::Simple,\n            PgType::Varchar => &PgTypeKind::Simple,\n            PgType::Date => &PgTypeKind::Simple,\n            PgType::Time => &PgTypeKind::Simple,\n            PgType::Timestamp => &PgTypeKind::Simple,\n            PgType::TimestampArray => &PgTypeKind::Array(PgTypeInfo(PgType::Timestamp)),\n            PgType::DateArray => &PgTypeKind::Array(PgTypeInfo(PgType::Date)),\n            PgType::TimeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Time)),\n            PgType::Timestamptz => &PgTypeKind::Simple,\n            PgType::TimestamptzArray => &PgTypeKind::Array(PgTypeInfo(PgType::Timestamptz)),\n            PgType::Interval => &PgTypeKind::Simple,\n            PgType::IntervalArray => &PgTypeKind::Array(PgTypeInfo(PgType::Interval)),\n            PgType::NumericArray => &PgTypeKind::Array(PgTypeInfo(PgType::Numeric)),\n            PgType::Timetz => &PgTypeKind::Simple,\n            PgType::TimetzArray => &PgTypeKind::Array(PgTypeInfo(PgType::Timetz)),\n            PgType::Bit => &PgTypeKind::Simple,\n            PgType::BitArray => &PgTypeKind::Array(PgTypeInfo(PgType::Bit)),\n            PgType::Varbit => &PgTypeKind::Simple,\n            PgType::VarbitArray => &PgTypeKind::Array(PgTypeInfo(PgType::Varbit)),\n            PgType::Numeric => &PgTypeKind::Simple,\n            PgType::Record => &PgTypeKind::Simple,\n            PgType::RecordArray => &PgTypeKind::Array(PgTypeInfo(PgType::Record)),\n            PgType::Uuid => &PgTypeKind::Simple,\n            PgType::UuidArray => &PgTypeKind::Array(PgTypeInfo(PgType::Uuid)),\n            PgType::Jsonb => &PgTypeKind::Simple,\n            PgType::JsonbArray => &PgTypeKind::Array(PgTypeInfo(PgType::Jsonb)),\n            PgType::Int4Range => &PgTypeKind::Range(PgTypeInfo::INT4),\n            PgType::Int4RangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Int4Range)),\n            PgType::NumRange => &PgTypeKind::Range(PgTypeInfo::NUMERIC),\n            PgType::NumRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::NumRange)),\n            PgType::TsRange => &PgTypeKind::Range(PgTypeInfo::TIMESTAMP),\n            PgType::TsRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::TsRange)),\n            PgType::TstzRange => &PgTypeKind::Range(PgTypeInfo::TIMESTAMPTZ),\n            PgType::TstzRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::TstzRange)),\n            PgType::DateRange => &PgTypeKind::Range(PgTypeInfo::DATE),\n            PgType::DateRangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::DateRange)),\n            PgType::Int8Range => &PgTypeKind::Range(PgTypeInfo::INT8),\n            PgType::Int8RangeArray => &PgTypeKind::Array(PgTypeInfo(PgType::Int8Range)),\n            PgType::Jsonpath => &PgTypeKind::Simple,\n            PgType::JsonpathArray => &PgTypeKind::Array(PgTypeInfo(PgType::Jsonpath)),\n            PgType::Money => &PgTypeKind::Simple,\n            PgType::MoneyArray => &PgTypeKind::Array(PgTypeInfo(PgType::Money)),\n\n            PgType::Void => &PgTypeKind::Pseudo,\n\n            PgType::Custom(ty) => &ty.kind,\n\n            PgType::DeclareWithOid(oid) => {\n                unreachable!(\"(bug) use of unresolved type declaration [oid={}]\", oid.0);\n            }\n            PgType::DeclareWithName(name) => {\n                unreachable!(\"(bug) use of unresolved type declaration [name={name}]\");\n            }\n            PgType::DeclareArrayOf(array) => {\n                unreachable!(\n                    \"(bug) use of unresolved type declaration [array of={}]\",\n                    array.elem_name\n                );\n            }\n        }\n    }\n\n    /// If `self` is an array type, return the type info for its element.\n    pub(crate) fn try_array_element(&self) -> Option<Cow<'_, PgTypeInfo>> {\n        // We explicitly match on all the `None` cases to ensure an exhaustive match.\n        match self {\n            PgType::Bool => None,\n            PgType::BoolArray => Some(Cow::Owned(PgTypeInfo(PgType::Bool))),\n            PgType::Bytea => None,\n            PgType::ByteaArray => Some(Cow::Owned(PgTypeInfo(PgType::Bytea))),\n            PgType::Char => None,\n            PgType::CharArray => Some(Cow::Owned(PgTypeInfo(PgType::Char))),\n            PgType::Name => None,\n            PgType::NameArray => Some(Cow::Owned(PgTypeInfo(PgType::Name))),\n            PgType::Int8 => None,\n            PgType::Int8Array => Some(Cow::Owned(PgTypeInfo(PgType::Int8))),\n            PgType::Int2 => None,\n            PgType::Int2Array => Some(Cow::Owned(PgTypeInfo(PgType::Int2))),\n            PgType::Int4 => None,\n            PgType::Int4Array => Some(Cow::Owned(PgTypeInfo(PgType::Int4))),\n            PgType::Text => None,\n            PgType::TextArray => Some(Cow::Owned(PgTypeInfo(PgType::Text))),\n            PgType::Oid => None,\n            PgType::OidArray => Some(Cow::Owned(PgTypeInfo(PgType::Oid))),\n            PgType::Json => None,\n            PgType::JsonArray => Some(Cow::Owned(PgTypeInfo(PgType::Json))),\n            PgType::Point => None,\n            PgType::PointArray => Some(Cow::Owned(PgTypeInfo(PgType::Point))),\n            PgType::Lseg => None,\n            PgType::LsegArray => Some(Cow::Owned(PgTypeInfo(PgType::Lseg))),\n            PgType::Path => None,\n            PgType::PathArray => Some(Cow::Owned(PgTypeInfo(PgType::Path))),\n            PgType::Box => None,\n            PgType::BoxArray => Some(Cow::Owned(PgTypeInfo(PgType::Box))),\n            PgType::Polygon => None,\n            PgType::PolygonArray => Some(Cow::Owned(PgTypeInfo(PgType::Polygon))),\n            PgType::Line => None,\n            PgType::LineArray => Some(Cow::Owned(PgTypeInfo(PgType::Line))),\n            PgType::Cidr => None,\n            PgType::CidrArray => Some(Cow::Owned(PgTypeInfo(PgType::Cidr))),\n            PgType::Float4 => None,\n            PgType::Float4Array => Some(Cow::Owned(PgTypeInfo(PgType::Float4))),\n            PgType::Float8 => None,\n            PgType::Float8Array => Some(Cow::Owned(PgTypeInfo(PgType::Float8))),\n            PgType::Circle => None,\n            PgType::CircleArray => Some(Cow::Owned(PgTypeInfo(PgType::Circle))),\n            PgType::Macaddr8 => None,\n            PgType::Macaddr8Array => Some(Cow::Owned(PgTypeInfo(PgType::Macaddr8))),\n            PgType::Money => None,\n            PgType::MoneyArray => Some(Cow::Owned(PgTypeInfo(PgType::Money))),\n            PgType::Macaddr => None,\n            PgType::MacaddrArray => Some(Cow::Owned(PgTypeInfo(PgType::Macaddr))),\n            PgType::Inet => None,\n            PgType::InetArray => Some(Cow::Owned(PgTypeInfo(PgType::Inet))),\n            PgType::Bpchar => None,\n            PgType::BpcharArray => Some(Cow::Owned(PgTypeInfo(PgType::Bpchar))),\n            PgType::Varchar => None,\n            PgType::VarcharArray => Some(Cow::Owned(PgTypeInfo(PgType::Varchar))),\n            PgType::Date => None,\n            PgType::DateArray => Some(Cow::Owned(PgTypeInfo(PgType::Date))),\n            PgType::Time => None,\n            PgType::TimeArray => Some(Cow::Owned(PgTypeInfo(PgType::Time))),\n            PgType::Timestamp => None,\n            PgType::TimestampArray => Some(Cow::Owned(PgTypeInfo(PgType::Timestamp))),\n            PgType::Timestamptz => None,\n            PgType::TimestamptzArray => Some(Cow::Owned(PgTypeInfo(PgType::Timestamptz))),\n            PgType::Interval => None,\n            PgType::IntervalArray => Some(Cow::Owned(PgTypeInfo(PgType::Interval))),\n            PgType::Timetz => None,\n            PgType::TimetzArray => Some(Cow::Owned(PgTypeInfo(PgType::Timetz))),\n            PgType::Bit => None,\n            PgType::BitArray => Some(Cow::Owned(PgTypeInfo(PgType::Bit))),\n            PgType::Varbit => None,\n            PgType::VarbitArray => Some(Cow::Owned(PgTypeInfo(PgType::Varbit))),\n            PgType::Numeric => None,\n            PgType::NumericArray => Some(Cow::Owned(PgTypeInfo(PgType::Numeric))),\n            PgType::Record => None,\n            PgType::RecordArray => Some(Cow::Owned(PgTypeInfo(PgType::Record))),\n            PgType::Uuid => None,\n            PgType::UuidArray => Some(Cow::Owned(PgTypeInfo(PgType::Uuid))),\n            PgType::Jsonb => None,\n            PgType::JsonbArray => Some(Cow::Owned(PgTypeInfo(PgType::Jsonb))),\n            PgType::Int4Range => None,\n            PgType::Int4RangeArray => Some(Cow::Owned(PgTypeInfo(PgType::Int4Range))),\n            PgType::NumRange => None,\n            PgType::NumRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::NumRange))),\n            PgType::TsRange => None,\n            PgType::TsRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::TsRange))),\n            PgType::TstzRange => None,\n            PgType::TstzRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::TstzRange))),\n            PgType::DateRange => None,\n            PgType::DateRangeArray => Some(Cow::Owned(PgTypeInfo(PgType::DateRange))),\n            PgType::Int8Range => None,\n            PgType::Int8RangeArray => Some(Cow::Owned(PgTypeInfo(PgType::Int8Range))),\n            PgType::Jsonpath => None,\n            PgType::JsonpathArray => Some(Cow::Owned(PgTypeInfo(PgType::Jsonpath))),\n            // There is no `UnknownArray`\n            PgType::Unknown => None,\n            // There is no `VoidArray`\n            PgType::Void => None,\n\n            PgType::Custom(ty) => match &ty.kind {\n                PgTypeKind::Simple => None,\n                PgTypeKind::Pseudo => None,\n                PgTypeKind::Domain(_) => None,\n                PgTypeKind::Composite(_) => None,\n                PgTypeKind::Array(ref elem_type_info) => Some(Cow::Borrowed(elem_type_info)),\n                PgTypeKind::Enum(_) => None,\n                PgTypeKind::Range(_) => None,\n            },\n            PgType::DeclareWithOid(_) => None,\n            PgType::DeclareWithName(name) => {\n                // LEGACY: infer the array element name from a `_` prefix\n                UStr::strip_prefix(name, \"_\")\n                    .map(|elem| Cow::Owned(PgTypeInfo(PgType::DeclareWithName(elem))))\n            }\n            PgType::DeclareArrayOf(array) => Some(Cow::Owned(PgTypeInfo(PgType::DeclareWithName(\n                array.elem_name.clone(),\n            )))),\n        }\n    }\n\n    /// Returns `true` if this type cannot be matched by name.\n    fn is_declare_with_oid(&self) -> bool {\n        matches!(self, Self::DeclareWithOid(_))\n    }\n\n    /// Compare two `PgType`s, first by OID, then by array element, then by name.\n    ///\n    /// If `soft_eq` is true and `self` or `other` is `DeclareWithOid` but not both, return `true`\n    /// before checking names.\n    fn eq_impl(&self, other: &Self, soft_eq: bool) -> bool {\n        if let (Some(a), Some(b)) = (self.try_base_oid(), other.try_base_oid()) {\n            // If there are OIDs available, use OIDs to perform a direct match\n            return a == b;\n        }\n\n        if soft_eq && (self.is_declare_with_oid() || other.is_declare_with_oid()) {\n            // If we get to this point, one instance is `DeclareWithOid()` and the other is\n            // `DeclareArrayOf()` or `DeclareWithName()`, which means we can't compare the two.\n            //\n            // Since this is only likely to occur when using the text protocol where we can't\n            // resolve type names before executing a query, we can just opt out of typechecking.\n            return true;\n        }\n\n        if let (Some(elem_a), Some(elem_b)) = (self.try_array_element(), other.try_array_element())\n        {\n            return elem_a == elem_b;\n        }\n\n        // Otherwise, perform a match on the name\n        name_eq(self.name(), other.name())\n    }\n\n    // Tries to return the OID of the type, returns the OID of the base_type for domain types\n    #[inline(always)]\n    fn try_base_oid(&self) -> Option<Oid> {\n        match self {\n            PgType::Custom(custom) => match &custom.kind {\n                PgTypeKind::Domain(domain) => domain.try_oid(),\n                _ => Some(custom.oid),\n            },\n            ty => ty.try_oid(),\n        }\n    }\n}\n\nimpl TypeInfo for PgTypeInfo {\n    fn name(&self) -> &str {\n        self.0.display_name()\n    }\n\n    fn is_null(&self) -> bool {\n        false\n    }\n\n    fn is_void(&self) -> bool {\n        matches!(self.0, PgType::Void)\n    }\n\n    fn type_compatible(&self, other: &Self) -> bool\n    where\n        Self: Sized,\n    {\n        self == other\n    }\n}\n\nimpl PartialEq<PgCustomType> for PgCustomType {\n    fn eq(&self, other: &PgCustomType) -> bool {\n        other.oid == self.oid\n    }\n}\n\nimpl PgTypeInfo {\n    // boolean, state of true or false\n    pub(crate) const BOOL: Self = Self(PgType::Bool);\n    pub(crate) const BOOL_ARRAY: Self = Self(PgType::BoolArray);\n\n    // binary data types, variable-length binary string\n    pub(crate) const BYTEA: Self = Self(PgType::Bytea);\n    pub(crate) const BYTEA_ARRAY: Self = Self(PgType::ByteaArray);\n\n    // uuid\n    pub(crate) const UUID: Self = Self(PgType::Uuid);\n    pub(crate) const UUID_ARRAY: Self = Self(PgType::UuidArray);\n\n    // record\n    pub(crate) const RECORD: Self = Self(PgType::Record);\n    pub(crate) const RECORD_ARRAY: Self = Self(PgType::RecordArray);\n\n    //\n    // JSON types\n    // https://www.postgresql.org/docs/current/datatype-json.html\n    //\n\n    pub(crate) const JSON: Self = Self(PgType::Json);\n    pub(crate) const JSON_ARRAY: Self = Self(PgType::JsonArray);\n\n    pub(crate) const JSONB: Self = Self(PgType::Jsonb);\n    pub(crate) const JSONB_ARRAY: Self = Self(PgType::JsonbArray);\n\n    pub(crate) const JSONPATH: Self = Self(PgType::Jsonpath);\n    pub(crate) const JSONPATH_ARRAY: Self = Self(PgType::JsonpathArray);\n\n    //\n    // network address types\n    // https://www.postgresql.org/docs/current/datatype-net-types.html\n    //\n\n    pub(crate) const CIDR: Self = Self(PgType::Cidr);\n    pub(crate) const CIDR_ARRAY: Self = Self(PgType::CidrArray);\n\n    pub(crate) const INET: Self = Self(PgType::Inet);\n    pub(crate) const INET_ARRAY: Self = Self(PgType::InetArray);\n\n    pub(crate) const MACADDR: Self = Self(PgType::Macaddr);\n    pub(crate) const MACADDR_ARRAY: Self = Self(PgType::MacaddrArray);\n\n    pub(crate) const MACADDR8: Self = Self(PgType::Macaddr8);\n    pub(crate) const MACADDR8_ARRAY: Self = Self(PgType::Macaddr8Array);\n\n    //\n    // character types\n    // https://www.postgresql.org/docs/current/datatype-character.html\n    //\n\n    // internal type for object names\n    pub(crate) const NAME: Self = Self(PgType::Name);\n    pub(crate) const NAME_ARRAY: Self = Self(PgType::NameArray);\n\n    // character type, fixed-length, blank-padded\n    pub(crate) const BPCHAR: Self = Self(PgType::Bpchar);\n    pub(crate) const BPCHAR_ARRAY: Self = Self(PgType::BpcharArray);\n\n    // character type, variable-length with limit\n    pub(crate) const VARCHAR: Self = Self(PgType::Varchar);\n    pub(crate) const VARCHAR_ARRAY: Self = Self(PgType::VarcharArray);\n\n    // character type, variable-length\n    pub(crate) const TEXT: Self = Self(PgType::Text);\n    pub(crate) const TEXT_ARRAY: Self = Self(PgType::TextArray);\n\n    // unknown type, transmitted as text\n    pub(crate) const UNKNOWN: Self = Self(PgType::Unknown);\n\n    //\n    // numeric types\n    // https://www.postgresql.org/docs/current/datatype-numeric.html\n    //\n\n    // single-byte internal type\n    pub(crate) const CHAR: Self = Self(PgType::Char);\n    pub(crate) const CHAR_ARRAY: Self = Self(PgType::CharArray);\n\n    // internal type for type ids\n    pub(crate) const OID: Self = Self(PgType::Oid);\n    pub(crate) const OID_ARRAY: Self = Self(PgType::OidArray);\n\n    // small-range integer; -32768 to +32767\n    pub(crate) const INT2: Self = Self(PgType::Int2);\n    pub(crate) const INT2_ARRAY: Self = Self(PgType::Int2Array);\n\n    // typical choice for integer; -2147483648 to +2147483647\n    pub(crate) const INT4: Self = Self(PgType::Int4);\n    pub(crate) const INT4_ARRAY: Self = Self(PgType::Int4Array);\n\n    // large-range integer; -9223372036854775808 to +9223372036854775807\n    pub(crate) const INT8: Self = Self(PgType::Int8);\n    pub(crate) const INT8_ARRAY: Self = Self(PgType::Int8Array);\n\n    // variable-precision, inexact, 6 decimal digits precision\n    pub(crate) const FLOAT4: Self = Self(PgType::Float4);\n    pub(crate) const FLOAT4_ARRAY: Self = Self(PgType::Float4Array);\n\n    // variable-precision, inexact, 15 decimal digits precision\n    pub(crate) const FLOAT8: Self = Self(PgType::Float8);\n    pub(crate) const FLOAT8_ARRAY: Self = Self(PgType::Float8Array);\n\n    // user-specified precision, exact\n    pub(crate) const NUMERIC: Self = Self(PgType::Numeric);\n    pub(crate) const NUMERIC_ARRAY: Self = Self(PgType::NumericArray);\n\n    // user-specified precision, exact\n    pub(crate) const MONEY: Self = Self(PgType::Money);\n    pub(crate) const MONEY_ARRAY: Self = Self(PgType::MoneyArray);\n\n    //\n    // date/time types\n    // https://www.postgresql.org/docs/current/datatype-datetime.html\n    //\n\n    // both date and time (no time zone)\n    pub(crate) const TIMESTAMP: Self = Self(PgType::Timestamp);\n    pub(crate) const TIMESTAMP_ARRAY: Self = Self(PgType::TimestampArray);\n\n    // both date and time (with time zone)\n    pub(crate) const TIMESTAMPTZ: Self = Self(PgType::Timestamptz);\n    pub(crate) const TIMESTAMPTZ_ARRAY: Self = Self(PgType::TimestamptzArray);\n\n    // date (no time of day)\n    pub(crate) const DATE: Self = Self(PgType::Date);\n    pub(crate) const DATE_ARRAY: Self = Self(PgType::DateArray);\n\n    // time of day (no date)\n    pub(crate) const TIME: Self = Self(PgType::Time);\n    pub(crate) const TIME_ARRAY: Self = Self(PgType::TimeArray);\n\n    // time of day (no date), with time zone\n    pub(crate) const TIMETZ: Self = Self(PgType::Timetz);\n    pub(crate) const TIMETZ_ARRAY: Self = Self(PgType::TimetzArray);\n\n    // time interval\n    pub(crate) const INTERVAL: Self = Self(PgType::Interval);\n    pub(crate) const INTERVAL_ARRAY: Self = Self(PgType::IntervalArray);\n\n    //\n    // geometric types\n    // https://www.postgresql.org/docs/current/datatype-geometric.html\n    //\n\n    // point on a plane\n    pub(crate) const POINT: Self = Self(PgType::Point);\n    pub(crate) const POINT_ARRAY: Self = Self(PgType::PointArray);\n\n    // infinite line\n    pub(crate) const LINE: Self = Self(PgType::Line);\n    pub(crate) const LINE_ARRAY: Self = Self(PgType::LineArray);\n\n    // finite line segment\n    pub(crate) const LSEG: Self = Self(PgType::Lseg);\n    pub(crate) const LSEG_ARRAY: Self = Self(PgType::LsegArray);\n\n    // rectangular box\n    pub(crate) const BOX: Self = Self(PgType::Box);\n    pub(crate) const BOX_ARRAY: Self = Self(PgType::BoxArray);\n\n    // open or closed path\n    pub(crate) const PATH: Self = Self(PgType::Path);\n    pub(crate) const PATH_ARRAY: Self = Self(PgType::PathArray);\n\n    // polygon\n    pub(crate) const POLYGON: Self = Self(PgType::Polygon);\n    pub(crate) const POLYGON_ARRAY: Self = Self(PgType::PolygonArray);\n\n    // circle\n    pub(crate) const CIRCLE: Self = Self(PgType::Circle);\n    pub(crate) const CIRCLE_ARRAY: Self = Self(PgType::CircleArray);\n\n    //\n    // bit string types\n    // https://www.postgresql.org/docs/current/datatype-bit.html\n    //\n\n    pub(crate) const BIT: Self = Self(PgType::Bit);\n    pub(crate) const BIT_ARRAY: Self = Self(PgType::BitArray);\n\n    pub(crate) const VARBIT: Self = Self(PgType::Varbit);\n    pub(crate) const VARBIT_ARRAY: Self = Self(PgType::VarbitArray);\n\n    //\n    // range types\n    // https://www.postgresql.org/docs/current/rangetypes.html\n    //\n\n    pub(crate) const INT4_RANGE: Self = Self(PgType::Int4Range);\n    pub(crate) const INT4_RANGE_ARRAY: Self = Self(PgType::Int4RangeArray);\n\n    pub(crate) const NUM_RANGE: Self = Self(PgType::NumRange);\n    pub(crate) const NUM_RANGE_ARRAY: Self = Self(PgType::NumRangeArray);\n\n    pub(crate) const TS_RANGE: Self = Self(PgType::TsRange);\n    pub(crate) const TS_RANGE_ARRAY: Self = Self(PgType::TsRangeArray);\n\n    pub(crate) const TSTZ_RANGE: Self = Self(PgType::TstzRange);\n    pub(crate) const TSTZ_RANGE_ARRAY: Self = Self(PgType::TstzRangeArray);\n\n    pub(crate) const DATE_RANGE: Self = Self(PgType::DateRange);\n    pub(crate) const DATE_RANGE_ARRAY: Self = Self(PgType::DateRangeArray);\n\n    pub(crate) const INT8_RANGE: Self = Self(PgType::Int8Range);\n    pub(crate) const INT8_RANGE_ARRAY: Self = Self(PgType::Int8RangeArray);\n\n    //\n    // pseudo types\n    // https://www.postgresql.org/docs/9.3/datatype-pseudo.html\n    //\n\n    pub(crate) const VOID: Self = Self(PgType::Void);\n}\n\nimpl Display for PgTypeInfo {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.pad(self.name())\n    }\n}\n\nimpl PartialEq<PgType> for PgType {\n    fn eq(&self, other: &PgType) -> bool {\n        self.eq_impl(other, true)\n    }\n}\n\n/// Check type names for equality, respecting Postgres' case sensitivity rules for identifiers.\n///\n/// https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS\nfn name_eq(name1: &str, name2: &str) -> bool {\n    // Cop-out of processing Unicode escapes by just using string equality.\n    if name1.starts_with(\"U&\") {\n        // If `name2` doesn't start with `U&` this will automatically be `false`.\n        return name1 == name2;\n    }\n\n    let mut chars1 = identifier_chars(name1);\n    let mut chars2 = identifier_chars(name2);\n\n    while let (Some(a), Some(b)) = (chars1.next(), chars2.next()) {\n        if !a.eq(&b) {\n            return false;\n        }\n    }\n\n    chars1.next().is_none() && chars2.next().is_none()\n}\n\nstruct IdentifierChar {\n    ch: char,\n    case_sensitive: bool,\n}\n\nimpl IdentifierChar {\n    fn eq(&self, other: &Self) -> bool {\n        if self.case_sensitive || other.case_sensitive {\n            self.ch == other.ch\n        } else {\n            self.ch.eq_ignore_ascii_case(&other.ch)\n        }\n    }\n}\n\n/// Return an iterator over all significant characters of an identifier.\n///\n/// Ignores non-escaped quotation marks.\nfn identifier_chars(ident: &str) -> impl Iterator<Item = IdentifierChar> + '_ {\n    let mut case_sensitive = false;\n    let mut last_char_quote = false;\n\n    ident.chars().filter_map(move |ch| {\n        if ch == '\"' {\n            if last_char_quote {\n                last_char_quote = false;\n            } else {\n                last_char_quote = true;\n                return None;\n            }\n        } else if last_char_quote {\n            last_char_quote = false;\n            case_sensitive = !case_sensitive;\n        }\n\n        Some(IdentifierChar { ch, case_sensitive })\n    })\n}\n\n#[test]\nfn test_name_eq() {\n    let test_values = [\n        (\"foo\", \"foo\", true),\n        (\"foo\", \"Foo\", true),\n        (\"foo\", \"FOO\", true),\n        (\"foo\", r#\"\"foo\"\"#, true),\n        (\"foo\", r#\"\"Foo\"\"#, false),\n        (\"foo\", \"foo.foo\", false),\n        (\"foo.foo\", \"foo.foo\", true),\n        (\"foo.foo\", \"foo.Foo\", true),\n        (\"foo.foo\", \"foo.FOO\", true),\n        (\"foo.foo\", \"Foo.foo\", true),\n        (\"foo.foo\", \"Foo.Foo\", true),\n        (\"foo.foo\", \"FOO.FOO\", true),\n        (\"foo.foo\", \"foo\", false),\n        (\"foo.foo\", r#\"foo.\"foo\"\"#, true),\n        (\"foo.foo\", r#\"foo.\"Foo\"\"#, false),\n        (\"foo.foo\", r#\"foo.\"FOO\"\"#, false),\n    ];\n\n    for (left, right, eq) in test_values {\n        assert_eq!(\n            name_eq(left, right),\n            eq,\n            \"failed check for name_eq({left:?}, {right:?})\"\n        );\n        assert_eq!(\n            name_eq(right, left),\n            eq,\n            \"failed check for name_eq({right:?}, {left:?})\"\n        );\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/array.rs",
    "content": "use sqlx_core::bytes::Buf;\nuse sqlx_core::types::Text;\nuse std::borrow::Cow;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Oid;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n/// Provides information necessary to encode and decode Postgres arrays as compatible Rust types.\n///\n/// Implementing this trait for some type `T` enables relevant `Type`,`Encode` and `Decode` impls\n/// for `Vec<T>`, `&[T]` (slices), `[T; N]` (arrays), etc.\n///\n/// ### Note: `#[derive(sqlx::Type)]`\n/// If you have the `postgres` feature enabled, `#[derive(sqlx::Type)]` will also generate\n/// an impl of this trait for your type if your wrapper is marked `#[sqlx(transparent)]`:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent)]\n/// struct UserId(i64);\n///\n/// let user_ids: Vec<UserId> = sqlx::query_scalar(\"select '{ 123, 456 }'::int8[]\")\n///    .fetch(&mut pg_connection)\n///    .await?;\n/// ```\n///\n/// However, this may cause an error if the type being wrapped does not implement `PgHasArrayType`,\n/// e.g. `Vec` itself, because we don't currently support multidimensional arrays:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)] // ERROR: `Vec<i64>` does not implement `PgHasArrayType`\n/// #[sqlx(transparent)]\n/// struct UserIds(Vec<i64>);\n/// ```\n///\n/// To remedy this, add `#[sqlx(no_pg_array)]`, which disables the generation\n/// of the `PgHasArrayType` impl:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent, no_pg_array)]\n/// struct UserIds(Vec<i64>);\n/// ```\n///\n/// See [the documentation of `Type`][Type] for more details.\npub trait PgHasArrayType {\n    fn array_type_info() -> PgTypeInfo;\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        *ty == Self::array_type_info()\n    }\n}\n\nimpl<T> PgHasArrayType for &T\nwhere\n    T: PgHasArrayType,\n{\n    fn array_type_info() -> PgTypeInfo {\n        T::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        T::array_compatible(ty)\n    }\n}\n\nimpl<T> PgHasArrayType for Option<T>\nwhere\n    T: PgHasArrayType,\n{\n    fn array_type_info() -> PgTypeInfo {\n        T::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        T::array_compatible(ty)\n    }\n}\n\nimpl<T> PgHasArrayType for Text<T> {\n    fn array_type_info() -> PgTypeInfo {\n        String::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        String::array_compatible(ty)\n    }\n}\n\nimpl<T> Type<Postgres> for [T]\nwhere\n    T: PgHasArrayType,\n{\n    fn type_info() -> PgTypeInfo {\n        T::array_type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        T::array_compatible(ty)\n    }\n}\n\nimpl<T> Type<Postgres> for Vec<T>\nwhere\n    T: PgHasArrayType,\n{\n    fn type_info() -> PgTypeInfo {\n        T::array_type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        T::array_compatible(ty)\n    }\n}\n\nimpl<T, const N: usize> Type<Postgres> for [T; N]\nwhere\n    T: PgHasArrayType,\n{\n    fn type_info() -> PgTypeInfo {\n        T::array_type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        T::array_compatible(ty)\n    }\n}\n\nimpl<'q, T> Encode<'q, Postgres> for Vec<T>\nwhere\n    for<'a> &'a [T]: Encode<'q, Postgres>,\n    T: Encode<'q, Postgres>,\n{\n    #[inline]\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.as_slice().encode_by_ref(buf)\n    }\n}\n\nimpl<'q, T, const N: usize> Encode<'q, Postgres> for [T; N]\nwhere\n    for<'a> &'a [T]: Encode<'q, Postgres>,\n    T: Encode<'q, Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.as_slice().encode_by_ref(buf)\n    }\n}\n\nimpl<'q, T> Encode<'q, Postgres> for &'_ [T]\nwhere\n    T: Encode<'q, Postgres> + Type<Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // do the length check early to avoid doing unnecessary work\n        i32::try_from(self.len()).map_err(|_| {\n            format!(\n                \"encoded array length is too large for Postgres: {}\",\n                self.len()\n            )\n        })?;\n        crate::PgBindIterExt::bind_iter(self.iter()).encode(buf)\n    }\n}\n\nimpl<'r, T, const N: usize> Decode<'r, Postgres> for [T; N]\nwhere\n    T: for<'a> Decode<'a, Postgres> + Type<Postgres>,\n{\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        // This could be done more efficiently by refactoring the Vec decoding below so that it can\n        // be used for arrays and Vec.\n        let vec: Vec<T> = Decode::decode(value)?;\n        let array: [T; N] = vec.try_into().map_err(|_| \"wrong number of elements\")?;\n        Ok(array)\n    }\n}\n\nimpl<'r, T> Decode<'r, Postgres> for Vec<T>\nwhere\n    T: for<'a> Decode<'a, Postgres> + Type<Postgres>,\n{\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let format = value.format();\n\n        match format {\n            PgValueFormat::Binary => {\n                // https://github.com/postgres/postgres/blob/a995b371ae29de2d38c4b7881cf414b1560e9746/src/backend/utils/adt/arrayfuncs.c#L1548\n\n                let mut buf = value.as_bytes()?;\n\n                // number of dimensions in the array\n                let ndim = buf.get_i32();\n\n                if ndim == 0 {\n                    // zero dimensions is an empty array\n                    return Ok(Vec::new());\n                }\n\n                if ndim != 1 {\n                    return Err(format!(\"encountered an array of {ndim} dimensions; only one-dimensional arrays are supported\").into());\n                }\n\n                // appears to have been used in the past to communicate potential NULLS\n                // but reading source code back through our historically supported\n                // postgres versions (9.5+) this is never used for anything\n                let _flags = buf.get_i32();\n\n                // the OID of the element\n                let element_type_oid = Oid(buf.get_u32());\n                let element_type_info: PgTypeInfo = PgTypeInfo::try_from_oid(element_type_oid)\n                    .or_else(|| value.type_info.try_array_element().map(Cow::into_owned))\n                    .ok_or_else(|| {\n                        BoxDynError::from(format!(\n                            \"failed to resolve array element type for oid {}\",\n                            element_type_oid.0\n                        ))\n                    })?;\n\n                // length of the array axis\n                let len = buf.get_i32();\n\n                let len = usize::try_from(len)\n                    .map_err(|_| format!(\"overflow converting array len ({len}) to usize\"))?;\n\n                // the lower bound, we only support arrays starting from \"1\"\n                let lower = buf.get_i32();\n\n                if lower != 1 {\n                    return Err(format!(\"encountered an array with a lower bound of {lower} in the first dimension; only arrays starting at one are supported\").into());\n                }\n\n                let mut elements = Vec::with_capacity(len);\n\n                for _ in 0..len {\n                    let value_ref = PgValueRef::get(&mut buf, format, element_type_info.clone())?;\n\n                    elements.push(T::decode(value_ref)?);\n                }\n\n                Ok(elements)\n            }\n\n            PgValueFormat::Text => {\n                // no type is provided from the database for the element\n                let element_type_info = T::type_info();\n\n                let s = value.as_str()?;\n\n                // https://github.com/postgres/postgres/blob/a995b371ae29de2d38c4b7881cf414b1560e9746/src/backend/utils/adt/arrayfuncs.c#L718\n\n                // trim the wrapping braces\n                let s = &s[1..(s.len() - 1)];\n\n                if s.is_empty() {\n                    // short-circuit empty arrays up here\n                    return Ok(Vec::new());\n                }\n\n                // NOTE: Nearly *all* types use ',' as the sequence delimiter. Yes, there is one\n                //       that does not. The BOX (not PostGIS) type uses ';' as a delimiter.\n\n                // TODO: When we add support for BOX we need to figure out some way to make the\n                //       delimiter selection\n\n                let delimiter = ',';\n                let mut done = false;\n                let mut in_quotes = false;\n                let mut in_escape = false;\n                let mut value = String::with_capacity(10);\n                let mut chars = s.chars();\n                let mut elements = Vec::with_capacity(4);\n\n                while !done {\n                    loop {\n                        match chars.next() {\n                            Some(ch) => match ch {\n                                _ if in_escape => {\n                                    value.push(ch);\n                                    in_escape = false;\n                                }\n\n                                '\"' => {\n                                    in_quotes = !in_quotes;\n                                }\n\n                                '\\\\' => {\n                                    in_escape = true;\n                                }\n\n                                _ if ch == delimiter && !in_quotes => {\n                                    break;\n                                }\n\n                                _ => {\n                                    value.push(ch);\n                                }\n                            },\n\n                            None => {\n                                done = true;\n                                break;\n                            }\n                        }\n                    }\n\n                    let value_opt = if value == \"NULL\" {\n                        None\n                    } else {\n                        Some(value.as_bytes())\n                    };\n\n                    elements.push(T::decode(PgValueRef {\n                        value: value_opt,\n                        row: None,\n                        type_info: element_type_info.clone(),\n                        format,\n                    })?);\n\n                    value.clear();\n                }\n\n                Ok(elements)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/bigdecimal-range.md",
    "content": "#### Note: `BigDecimal` Has a Larger Range than `NUMERIC`\n`BigDecimal` can represent values with a far, far greater range than the `NUMERIC` type in Postgres can.\n\n`NUMERIC` is limited to 131,072 digits before the decimal point, and 16,384 digits after it. \nSee [Section 8.1, Numeric Types] of the Postgres manual for details.\n\nMeanwhile, `BigDecimal` can theoretically represent a value with an arbitrary number of decimal digits, albeit\nwith a maximum of 2<sup>63</sup> significant figures.\n\nBecause encoding in the current API design _must_ be infallible, \nwhen attempting to encode a `BigDecimal` that cannot fit in the wire representation of `NUMERIC`, \nSQLx may instead encode a sentinel value that falls outside the allowed range but is still representable.\n\nThis will cause the query to return a `DatabaseError` with code `22P03` (`invalid_binary_representation`)\nand the error message `invalid scale in external \"numeric\" value` (though this may be subject to change).\n\nHowever, `BigDecimal` should be able to decode any `NUMERIC` value except `NaN`, \nfor which it has no representation.\n\n[Section 8.1, Numeric Types]: https://www.postgresql.org/docs/current/datatype-numeric.html\n"
  },
  {
    "path": "sqlx-postgres/src/types/bigdecimal.rs",
    "content": "use bigdecimal::BigDecimal;\nuse num_bigint::{BigInt, Sign};\nuse std::cmp;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::numeric::{PgNumeric, PgNumericSign};\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl Type<Postgres> for BigDecimal {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::NUMERIC\n    }\n}\n\nimpl PgHasArrayType for BigDecimal {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::NUMERIC_ARRAY\n    }\n}\n\nimpl TryFrom<PgNumeric> for BigDecimal {\n    type Error = BoxDynError;\n\n    fn try_from(numeric: PgNumeric) -> Result<Self, BoxDynError> {\n        Self::try_from(&numeric)\n    }\n}\n\nimpl TryFrom<&'_ PgNumeric> for BigDecimal {\n    type Error = BoxDynError;\n\n    fn try_from(numeric: &'_ PgNumeric) -> Result<Self, Self::Error> {\n        let (digits, sign, weight) = match *numeric {\n            PgNumeric::Number {\n                ref digits,\n                sign,\n                weight,\n                ..\n            } => (digits, sign, weight),\n\n            PgNumeric::NotANumber => {\n                return Err(\"BigDecimal does not support NaN values\".into());\n            }\n        };\n\n        if digits.is_empty() {\n            // Postgres returns an empty digit array for 0 but BigInt expects at least one zero\n            return Ok(0u64.into());\n        }\n\n        let sign = match sign {\n            PgNumericSign::Positive => Sign::Plus,\n            PgNumericSign::Negative => Sign::Minus,\n        };\n\n        // weight is 0 if the decimal point falls after the first base-10000 digit\n        //\n        // `Vec` capacity cannot exceed `isize::MAX` bytes, so this cast can't wrap in practice.\n        #[allow(clippy::cast_possible_wrap)]\n        let scale = (digits.len() as i64 - weight as i64 - 1) * 4;\n\n        // no optimized algorithm for base-10 so use base-100 for faster processing\n        let mut cents = Vec::with_capacity(digits.len() * 2);\n\n        #[allow(\n            clippy::cast_possible_truncation,\n            clippy::cast_possible_wrap,\n            clippy::cast_sign_loss\n        )]\n        for (i, &digit) in digits.iter().enumerate() {\n            if !PgNumeric::is_valid_digit(digit) {\n                return Err(format!(\n                    \"PgNumeric to BigDecimal: {i}th digit is out of range {digit}\"\n                )\n                .into());\n            }\n\n            cents.push((digit / 100) as u8);\n            cents.push((digit % 100) as u8);\n        }\n\n        let bigint = BigInt::from_radix_be(sign, &cents, 100)\n            .ok_or(\"PgNumeric contained an out-of-range digit\")?;\n\n        Ok(BigDecimal::new(bigint, scale))\n    }\n}\n\nimpl TryFrom<&'_ BigDecimal> for PgNumeric {\n    type Error = BoxDynError;\n\n    fn try_from(decimal: &BigDecimal) -> Result<Self, BoxDynError> {\n        let base_10_to_10000 = |chunk: &[u8]| chunk.iter().fold(0i16, |a, &d| a * 10 + d as i16);\n\n        // NOTE: this unfortunately copies the BigInt internally\n        let (integer, exp) = decimal.as_bigint_and_exponent();\n\n        // this routine is specifically optimized for base-10\n        // FIXME: is there a way to iterate over the digits to avoid the Vec allocation\n        let (sign, base_10) = integer.to_radix_be(10);\n\n        let base_10_len = i64::try_from(base_10.len()).map_err(|_| {\n            format!(\n                \"BigDecimal base-10 length out of range for PgNumeric: {}\",\n                base_10.len()\n            )\n        })?;\n\n        // weight is positive power of 10000\n        // exp is the negative power of 10\n        let weight_10 = base_10_len - exp;\n\n        // scale is only nonzero when we have fractional digits\n        // since `exp` is the _negative_ decimal exponent, it tells us\n        // exactly what our scale should be\n        let scale: i16 = cmp::max(0, exp).try_into()?;\n\n        // there's an implicit +1 offset in the interpretation\n        let weight: i16 = if weight_10 <= 0 {\n            weight_10 / 4 - 1\n        } else {\n            // the `-1` is a fix for an off by 1 error (4 digits should still be 0 weight)\n            (weight_10 - 1) / 4\n        }\n        .try_into()?;\n\n        let digits_len = if base_10.len() % 4 != 0 {\n            base_10.len() / 4 + 1\n        } else {\n            base_10.len() / 4\n        };\n\n        // For efficiency, we want to process the base-10 digits in chunks of 4,\n        // but that means we need to deal with the non-divisible remainder first.\n        let offset = weight_10.rem_euclid(4);\n\n        // Do a checked conversion to the smallest integer,\n        // so we can widen arbitrarily without triggering lints.\n        let offset = u8::try_from(offset).unwrap_or_else(|_| {\n            panic!(\"BUG: `offset` should be in the range [0, 4) but is {offset}\")\n        });\n\n        let mut digits = Vec::with_capacity(digits_len);\n\n        if let Some(first) = base_10.get(..offset as usize) {\n            if !first.is_empty() {\n                digits.push(base_10_to_10000(first));\n            }\n        } else if offset != 0 {\n            // If we didn't hit the `if let Some` branch,\n            // then `base_10.len()` must strictly be smaller\n            #[allow(clippy::cast_possible_truncation)]\n            let power = (offset as usize - base_10.len()) as u32;\n\n            digits.push(base_10_to_10000(&base_10) * 10i16.pow(power));\n        }\n\n        if let Some(rest) = base_10.get(offset as usize..) {\n            // `chunk.len()` is always between 1 and 4\n            #[allow(clippy::cast_possible_truncation)]\n            digits.extend(\n                rest.chunks(4)\n                    .map(|chunk| base_10_to_10000(chunk) * 10i16.pow(4 - chunk.len() as u32)),\n            );\n        }\n\n        while let Some(&0) = digits.last() {\n            digits.pop();\n        }\n\n        Ok(PgNumeric::Number {\n            sign: sign_to_pg(sign),\n            scale,\n            weight,\n            digits,\n        })\n    }\n}\n\n#[doc=include_str!(\"bigdecimal-range.md\")]\nimpl Encode<'_, Postgres> for BigDecimal {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        PgNumeric::try_from(self)?.encode(buf)?;\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        PgNumeric::size_hint(self.digits())\n    }\n}\n\n/// ### Note: `NaN`\n/// `BigDecimal` has a greater range than `NUMERIC` (see the corresponding `Encode` impl for details)\n/// but cannot represent `NaN`, so decoding may return an error.\nimpl Decode<'_, Postgres> for BigDecimal {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => PgNumeric::decode(value.as_bytes()?)?.try_into(),\n            PgValueFormat::Text => Ok(value.as_str()?.parse::<BigDecimal>()?),\n        }\n    }\n}\n\nfn sign_to_pg(sign: Sign) -> PgNumericSign {\n    match sign {\n        Sign::Plus | Sign::NoSign => PgNumericSign::Positive,\n        Sign::Minus => PgNumericSign::Negative,\n    }\n}\n\n#[cfg(test)]\n#[allow(clippy::zero_prefixed_literal)] // Used for clarity\nmod tests {\n    use super::{BigDecimal, PgNumeric, PgNumericSign};\n    use std::convert::TryFrom;\n\n    #[test]\n    fn zero() {\n        let zero: BigDecimal = \"0\".parse().unwrap();\n\n        assert_eq!(\n            PgNumeric::try_from(&zero).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![]\n            }\n        );\n    }\n\n    #[test]\n    fn one() {\n        let one: BigDecimal = \"1\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&one).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![1]\n            }\n        );\n    }\n\n    #[test]\n    fn ten() {\n        let ten: BigDecimal = \"10\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&ten).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![10]\n            }\n        );\n    }\n\n    #[test]\n    fn one_hundred() {\n        let one_hundred: BigDecimal = \"100\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&one_hundred).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![100]\n            }\n        );\n    }\n\n    #[test]\n    fn ten_thousand() {\n        // BigDecimal doesn't normalize here\n        let ten_thousand: BigDecimal = \"10000\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&ten_thousand).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 1,\n                digits: vec![1]\n            }\n        );\n    }\n\n    #[test]\n    fn two_digits() {\n        let two_digits: BigDecimal = \"12345\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&two_digits).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 1,\n                digits: vec![1, 2345]\n            }\n        );\n    }\n\n    #[test]\n    fn one_tenth() {\n        let one_tenth: BigDecimal = \"0.1\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&one_tenth).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 1,\n                weight: -1,\n                digits: vec![1000]\n            }\n        );\n    }\n\n    #[test]\n    fn one_hundredth() {\n        let one_hundredth: BigDecimal = \"0.01\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&one_hundredth).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 2,\n                weight: -1,\n                digits: vec![100]\n            }\n        );\n    }\n\n    #[test]\n    fn twelve_thousandths() {\n        let twelve_thousandths: BigDecimal = \"0.012\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&twelve_thousandths).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 3,\n                weight: -1,\n                digits: vec![120]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_1() {\n        let decimal: BigDecimal = \"1.2345\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&decimal).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 4,\n                weight: 0,\n                digits: vec![1, 2345]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_2() {\n        let decimal: BigDecimal = \"0.12345\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&decimal).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 5,\n                weight: -1,\n                digits: vec![1234, 5000]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_3() {\n        let decimal: BigDecimal = \"0.01234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&decimal).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 5,\n                weight: -1,\n                digits: vec![0123, 4000]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_4() {\n        let decimal: BigDecimal = \"12345.67890\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&decimal).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 5,\n                weight: 1,\n                digits: vec![1, 2345, 6789]\n            }\n        );\n    }\n\n    #[test]\n    fn one_digit_decimal() {\n        let one_digit_decimal: BigDecimal = \"0.00001234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&one_digit_decimal).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 8,\n                weight: -2,\n                digits: vec![1234]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_four_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let four_digit: BigDecimal = \"1234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&four_digit).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![1234]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_negative_four_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let negative_four_digit: BigDecimal = \"-1234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&negative_four_digit).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Negative,\n                scale: 0,\n                weight: 0,\n                digits: vec![1234]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_eight_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let eight_digit: BigDecimal = \"12345678\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&eight_digit).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 1,\n                digits: vec![1234, 5678]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_negative_eight_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let negative_eight_digit: BigDecimal = \"-12345678\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::try_from(&negative_eight_digit).unwrap(),\n            PgNumeric::Number {\n                sign: PgNumericSign::Negative,\n                scale: 0,\n                weight: 1,\n                digits: vec![1234, 5678]\n            }\n        );\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/bit_vec.rs",
    "content": "use crate::arguments::value_size_int4_checked;\nuse crate::{\n    decode::Decode,\n    encode::{Encode, IsNull},\n    error::BoxDynError,\n    types::Type,\n    PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres,\n};\nuse bit_vec::BitVec;\nuse sqlx_core::bytes::Buf;\nuse std::{io, mem};\n\nimpl Type<Postgres> for BitVec {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::VARBIT\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::BIT || *ty == PgTypeInfo::VARBIT\n    }\n}\n\nimpl PgHasArrayType for BitVec {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::VARBIT_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::BIT_ARRAY || *ty == PgTypeInfo::VARBIT_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for BitVec {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        let len = value_size_int4_checked(self.len())?;\n\n        buf.extend(len.to_be_bytes());\n        buf.extend(self.to_bytes());\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i32>() + self.len()\n    }\n}\n\nimpl Decode<'_, Postgres> for BitVec {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => {\n                let mut bytes = value.as_bytes()?;\n                let len = bytes.get_i32();\n\n                let len = usize::try_from(len).map_err(|_| format!(\"invalid VARBIT len: {len}\"))?;\n\n                // The smallest amount of data we can read is one byte\n                let bytes_len = len.div_ceil(8);\n\n                if bytes.remaining() != bytes_len {\n                    Err(io::Error::new(\n                        io::ErrorKind::InvalidData,\n                        \"VARBIT length mismatch.\",\n                    ))?;\n                }\n\n                let mut bitvec = BitVec::from_bytes(bytes);\n\n                // Chop off zeroes from the back. We get bits in bytes, so if\n                // our bitvec is not in full bytes, extra zeroes are added to\n                // the end.\n                while bitvec.len() > len {\n                    bitvec.pop();\n                }\n\n                Ok(bitvec)\n            }\n            PgValueFormat::Text => {\n                let s = value.as_str()?;\n                let mut bit_vec = BitVec::with_capacity(s.len());\n\n                for c in s.chars() {\n                    match c {\n                        '0' => bit_vec.push(false),\n                        '1' => bit_vec.push(true),\n                        _ => {\n                            Err(io::Error::new(\n                                io::ErrorKind::InvalidData,\n                                \"VARBIT data contains other characters than 1 or 0.\",\n                            ))?;\n                        }\n                    }\n                }\n\n                Ok(bit_vec)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/bool.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl Type<Postgres> for bool {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::BOOL\n    }\n}\n\nimpl PgHasArrayType for bool {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::BOOL_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for bool {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.push(*self as u8);\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for bool {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => value.as_bytes()?[0] != 0,\n\n            PgValueFormat::Text => match value.as_str()? {\n                \"t\" => true,\n                \"f\" => false,\n\n                s => {\n                    return Err(format!(\"unexpected value {s:?} for boolean\").into());\n                }\n            },\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/bytes.rs",
    "content": "use std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl PgHasArrayType for u8 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::BYTEA\n    }\n}\n\nimpl PgHasArrayType for &'_ [u8] {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::BYTEA_ARRAY\n    }\n}\n\nimpl PgHasArrayType for Box<[u8]> {\n    fn array_type_info() -> PgTypeInfo {\n        <[&[u8]] as Type<Postgres>>::type_info()\n    }\n}\n\nimpl PgHasArrayType for Vec<u8> {\n    fn array_type_info() -> PgTypeInfo {\n        <[&[u8]] as Type<Postgres>>::type_info()\n    }\n}\n\nimpl<const N: usize> PgHasArrayType for [u8; N] {\n    fn array_type_info() -> PgTypeInfo {\n        <[&[u8]] as Type<Postgres>>::type_info()\n    }\n}\n\nimpl Encode<'_, Postgres> for &'_ [u8] {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend_from_slice(self);\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, Postgres> for Vec<u8> {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        <&[u8] as Encode<Postgres>>::encode(self, buf)\n    }\n}\n\nimpl<const N: usize> Encode<'_, Postgres> for [u8; N] {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        <&[u8] as Encode<Postgres>>::encode(self.as_slice(), buf)\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for &'r [u8] {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => value.as_bytes(),\n            PgValueFormat::Text => {\n                Err(\"unsupported decode to `&[u8]` of BYTEA in a simple query; use a prepared query or decode to `Vec<u8>`\".into())\n            }\n        }\n    }\n}\n\nfn text_hex_decode_input(value: PgValueRef<'_>) -> Result<&[u8], BoxDynError> {\n    // BYTEA is formatted as \\x followed by hex characters\n    value\n        .as_bytes()?\n        .strip_prefix(b\"\\\\x\")\n        .ok_or(\"text does not start with \\\\x\")\n        .map_err(Into::into)\n}\n\nimpl Decode<'_, Postgres> for Vec<u8> {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => value.as_bytes()?.to_owned(),\n            PgValueFormat::Text => hex::decode(text_hex_decode_input(value)?)?,\n        })\n    }\n}\n\nimpl<const N: usize> Decode<'_, Postgres> for [u8; N] {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        let mut bytes = [0u8; N];\n        match value.format() {\n            PgValueFormat::Binary => {\n                bytes = value.as_bytes()?.try_into()?;\n            }\n            PgValueFormat::Text => hex::decode_to_slice(text_hex_decode_input(value)?, &mut bytes)?,\n        };\n        Ok(bytes)\n    }\n}\n\nforward_encode_impl!(Arc<[u8]>, &[u8], Postgres);\nforward_encode_impl!(Rc<[u8]>, &[u8], Postgres);\nforward_encode_impl!(Box<[u8]>, &[u8], Postgres);\nforward_encode_impl!(Cow<'_, [u8]>, &[u8], Postgres);\n"
  },
  {
    "path": "sqlx-postgres/src/types/chrono/date.rs",
    "content": "use std::mem;\n\nuse chrono::{NaiveDate, TimeDelta};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl Type<Postgres> for NaiveDate {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE\n    }\n}\n\nimpl PgHasArrayType for NaiveDate {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for NaiveDate {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // DATE is encoded as the days since epoch\n        let days: i32 = (*self - postgres_epoch_date())\n            .num_days()\n            .try_into()\n            .map_err(|_| {\n                format!(\"value {self:?} would overflow binary encoding for Postgres DATE\")\n            })?;\n\n        Encode::<Postgres>::encode(days, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i32>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for NaiveDate {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                // DATE is encoded as the days since epoch\n                let days: i32 = Decode::<Postgres>::decode(value)?;\n\n                let days = TimeDelta::try_days(days.into())\n                    .unwrap_or_else(|| {\n                        unreachable!(\"BUG: days ({days}) as `i32` multiplied into seconds should not overflow `i64`\")\n                    });\n\n                postgres_epoch_date() + days\n            }\n\n            PgValueFormat::Text => NaiveDate::parse_from_str(value.as_str()?, \"%Y-%m-%d\")?,\n        })\n    }\n}\n\n#[inline]\nfn postgres_epoch_date() -> NaiveDate {\n    NaiveDate::from_ymd_opt(2000, 1, 1).expect(\"expected 2000-01-01 to be a valid NaiveDate\")\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/chrono/datetime.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse chrono::{\n    DateTime, Duration, FixedOffset, Local, NaiveDate, NaiveDateTime, Offset, TimeZone, Utc,\n};\nuse std::mem;\n\nimpl Type<Postgres> for NaiveDateTime {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMP\n    }\n}\n\nimpl<Tz: TimeZone> Type<Postgres> for DateTime<Tz> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMPTZ\n    }\n}\n\nimpl PgHasArrayType for NaiveDateTime {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMP_ARRAY\n    }\n}\n\nimpl<Tz: TimeZone> PgHasArrayType for DateTime<Tz> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMPTZ_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for NaiveDateTime {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // TIMESTAMP is encoded as the microseconds since the epoch\n        let micros = (*self - postgres_epoch_datetime())\n            .num_microseconds()\n            .ok_or_else(|| format!(\"NaiveDateTime out of range for Postgres: {self:?}\"))?;\n\n        Encode::<Postgres>::encode(micros, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i64>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for NaiveDateTime {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                // TIMESTAMP is encoded as the microseconds since the epoch\n                let us = Decode::<Postgres>::decode(value)?;\n                postgres_epoch_datetime() + Duration::microseconds(us)\n            }\n\n            PgValueFormat::Text => {\n                let s = value.as_str()?;\n                NaiveDateTime::parse_from_str(\n                    s,\n                    if s.contains('+') {\n                        // Contains a time-zone specifier\n                        // This is given for timestamptz for some reason\n                        // Postgres already guarantees this to always be UTC\n                        \"%Y-%m-%d %H:%M:%S%.f%#z\"\n                    } else {\n                        \"%Y-%m-%d %H:%M:%S%.f\"\n                    },\n                )?\n            }\n        })\n    }\n}\n\nimpl<Tz: TimeZone> Encode<'_, Postgres> for DateTime<Tz> {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Postgres>::encode(self.naive_utc(), buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i64>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for DateTime<Local> {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let fixed = <DateTime<FixedOffset> as Decode<Postgres>>::decode(value)?;\n        Ok(Local.from_utc_datetime(&fixed.naive_utc()))\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for DateTime<Utc> {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let fixed = <DateTime<FixedOffset> as Decode<Postgres>>::decode(value)?;\n        Ok(Utc.from_utc_datetime(&fixed.naive_utc()))\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for DateTime<FixedOffset> {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                let naive = <NaiveDateTime as Decode<Postgres>>::decode(value)?;\n                Utc.fix().from_utc_datetime(&naive)\n            }\n\n            PgValueFormat::Text => {\n                let s = value.as_str()?;\n                DateTime::parse_from_str(\n                    s,\n                    if s.contains('+') || s.contains('-') {\n                        // Contains a time-zone specifier\n                        // This is given for timestamptz for some reason\n                        // Postgres already guarantees this to always be UTC\n                        \"%Y-%m-%d %H:%M:%S%.f%#z\"\n                    } else {\n                        \"%Y-%m-%d %H:%M:%S%.f\"\n                    },\n                )?\n            }\n        })\n    }\n}\n\n#[inline]\nfn postgres_epoch_datetime() -> NaiveDateTime {\n    NaiveDate::from_ymd_opt(2000, 1, 1)\n        .expect(\"expected 2000-01-01 to be a valid NaiveDate\")\n        .and_hms_opt(0, 0, 0)\n        .expect(\"expected 2000-01-01T00:00:00 to be a valid NaiveDateTime\")\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/chrono/mod.rs",
    "content": "mod date;\nmod datetime;\nmod time;\n"
  },
  {
    "path": "sqlx-postgres/src/types/chrono/time.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse chrono::{Duration, NaiveTime};\nuse std::mem;\n\nimpl Type<Postgres> for NaiveTime {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TIME\n    }\n}\n\nimpl PgHasArrayType for NaiveTime {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIME_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for NaiveTime {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // TIME is encoded as the microseconds since midnight\n        let micros = (*self - NaiveTime::default())\n            .num_microseconds()\n            .ok_or_else(|| format!(\"Time out of range for PostgreSQL: {self}\"))?;\n\n        Encode::<Postgres>::encode(micros, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<u64>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for NaiveTime {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                // TIME is encoded as the microseconds since midnight\n                let us: i64 = Decode::<Postgres>::decode(value)?;\n                NaiveTime::default() + Duration::microseconds(us)\n            }\n\n            PgValueFormat::Text => NaiveTime::parse_from_str(value.as_str()?, \"%H:%M:%S%.f\")?,\n        })\n    }\n}\n\n#[test]\nfn check_naive_time_default_is_midnight() {\n    // Just a canary in case this changes.\n    assert_eq!(\n        NaiveTime::from_hms_opt(0, 0, 0),\n        Some(NaiveTime::default()),\n        \"implementation assumes `NaiveTime::default()` equals midnight\"\n    );\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/citext.rs",
    "content": "use crate::types::array_compatible;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};\nuse sqlx_core::decode::Decode;\nuse sqlx_core::encode::{Encode, IsNull};\nuse sqlx_core::error::BoxDynError;\nuse sqlx_core::types::Type;\nuse std::fmt;\nuse std::fmt::{Debug, Display, Formatter};\nuse std::ops::Deref;\nuse std::str::FromStr;\n\n/// Case-insensitive text (`citext`) support for Postgres.\n///\n/// Note that SQLx considers the `citext` type to be compatible with `String`\n/// and its various derivatives, so direct usage of this type is generally unnecessary.\n///\n/// However, it may be needed, for example, when binding a `citext[]` array,\n/// as Postgres will generally not accept a `text[]` array (mapped from `Vec<String>`) in its place.\n///\n/// See [the Postgres manual, Appendix F, Section 10][PG.F.10] for details on using `citext`.\n///\n/// [PG.F.10]: https://www.postgresql.org/docs/current/citext.html\n///\n/// ### Note: Extension Required\n/// The `citext` extension is not enabled by default in Postgres. You will need to do so explicitly:\n///\n/// ```ignore\n/// CREATE EXTENSION IF NOT EXISTS \"citext\";\n/// ```\n///\n/// ### Note: `PartialEq` is Case-Sensitive\n/// This type derives `PartialEq` which forwards to the implementation on `String`, which\n/// is case-sensitive. This impl exists mainly for testing.\n///\n/// To properly emulate the case-insensitivity of `citext` would require use of locale-aware\n/// functions in `libc`, and even then would require querying the locale of the database server\n/// and setting it locally, which is unsafe.\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct PgCiText(pub String);\n\nimpl Type<Postgres> for PgCiText {\n    fn type_info() -> PgTypeInfo {\n        // Since `citext` is enabled by an extension, it does not have a stable OID.\n        PgTypeInfo::with_name(\"citext\")\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        <&str as Type<Postgres>>::compatible(ty)\n    }\n}\n\nimpl Deref for PgCiText {\n    type Target = str;\n\n    fn deref(&self) -> &Self::Target {\n        self.0.as_str()\n    }\n}\n\nimpl From<String> for PgCiText {\n    fn from(value: String) -> Self {\n        Self(value)\n    }\n}\n\nimpl From<PgCiText> for String {\n    fn from(value: PgCiText) -> Self {\n        value.0\n    }\n}\n\nimpl FromStr for PgCiText {\n    type Err = core::convert::Infallible;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(PgCiText(s.parse()?))\n    }\n}\n\nimpl Display for PgCiText {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.write_str(&self.0)\n    }\n}\n\nimpl PgHasArrayType for PgCiText {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_citext\")\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        array_compatible::<&str>(ty)\n    }\n}\n\nimpl Encode<'_, Postgres> for PgCiText {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        <&str as Encode<Postgres>>::encode(&**self, buf)\n    }\n}\n\nimpl Decode<'_, Postgres> for PgCiText {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(PgCiText(value.as_str()?.to_owned()))\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/cube.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse sqlx_core::Error;\nuse std::mem;\nuse std::str::FromStr;\n\nconst BYTE_WIDTH: usize = 8;\n\n/// <https://github.com/postgres/postgres/blob/e3ec9dc1bf4983fcedb6f43c71ea12ee26aefc7a/contrib/cube/cubedata.h#L7>\nconst MAX_DIMENSIONS: usize = 100;\n\nconst IS_POINT_FLAG: u32 = 1 << 31;\n\n// FIXME(breaking): these variants are confusingly named and structured\n// consider changing them or making this an opaque wrapper around `Vec<f64>`\n#[derive(Debug, Clone, PartialEq)]\npub enum PgCube {\n    /// A one-dimensional point.\n    // FIXME: `Point1D(f64)`\n    Point(f64),\n    /// An N-dimensional point (\"represented internally as a zero-volume cube\").\n    // FIXME: `PointND(f64)`\n    ZeroVolume(Vec<f64>),\n\n    /// A one-dimensional interval with starting and ending points.\n    // FIXME: `Interval1D { start: f64, end: f64 }`\n    OneDimensionInterval(f64, f64),\n\n    // FIXME: add `Cube3D { lower_left: [f64; 3], upper_right: [f64; 3] }`?\n    /// An N-dimensional cube with points representing lower-left and upper-right corners, respectively.\n    // FIXME: `CubeND { lower_left: Vec<f64>, upper_right: Vec<f64> }`\n    MultiDimension(Vec<Vec<f64>>),\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\nstruct Header {\n    dimensions: usize,\n    is_point: bool,\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"error decoding CUBE (is_point: {is_point}, dimensions: {dimensions})\")]\nstruct DecodeError {\n    is_point: bool,\n    dimensions: usize,\n    message: String,\n}\n\nimpl Type<Postgres> for PgCube {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"cube\")\n    }\n}\n\nimpl PgHasArrayType for PgCube {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_cube\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgCube {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgCube::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgCube::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgCube {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"cube\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        self.header().encoded_size()\n    }\n}\n\nimpl FromStr for PgCube {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let content = s\n            .trim_start_matches('(')\n            .trim_start_matches('[')\n            .trim_end_matches(')')\n            .trim_end_matches(']')\n            .replace(' ', \"\");\n\n        if !content.contains('(') && !content.contains(',') {\n            return parse_point(&content);\n        }\n\n        if !content.contains(\"),(\") {\n            return parse_zero_volume(&content);\n        }\n\n        let point_vecs = content.split(\"),(\").collect::<Vec<&str>>();\n        if point_vecs.len() == 2 && !point_vecs.iter().any(|pv| pv.contains(',')) {\n            return parse_one_dimensional_interval(point_vecs);\n        }\n\n        parse_multidimensional_interval(point_vecs)\n    }\n}\n\nimpl PgCube {\n    fn header(&self) -> Header {\n        match self {\n            PgCube::Point(..) => Header {\n                is_point: true,\n                dimensions: 1,\n            },\n            PgCube::ZeroVolume(values) => Header {\n                is_point: true,\n                dimensions: values.len(),\n            },\n            PgCube::OneDimensionInterval(..) => Header {\n                is_point: false,\n                dimensions: 1,\n            },\n            PgCube::MultiDimension(multi_values) => Header {\n                is_point: false,\n                dimensions: multi_values.first().map(|arr| arr.len()).unwrap_or(0),\n            },\n        }\n    }\n\n    fn from_bytes(mut bytes: &[u8]) -> Result<Self, BoxDynError> {\n        let header = Header::try_read(&mut bytes)?;\n\n        if bytes.len() != header.data_size() {\n            return Err(DecodeError::new(\n                &header,\n                format!(\n                    \"expected {} bytes after header, got {}\",\n                    header.data_size(),\n                    bytes.len()\n                ),\n            )\n            .into());\n        }\n\n        match (header.is_point, header.dimensions) {\n            (true, 1) => Ok(PgCube::Point(bytes.get_f64())),\n            (true, _) => Ok(PgCube::ZeroVolume(\n                read_vec(&mut bytes).map_err(|e| DecodeError::new(&header, e))?,\n            )),\n            (false, 1) => Ok(PgCube::OneDimensionInterval(\n                bytes.get_f64(),\n                bytes.get_f64(),\n            )),\n            (false, _) => Ok(PgCube::MultiDimension(read_cube(&header, bytes)?)),\n        }\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), String> {\n        let header = self.header();\n\n        buff.reserve(header.data_size());\n\n        header.try_write(buff)?;\n\n        match self {\n            PgCube::Point(value) => {\n                buff.extend_from_slice(&value.to_be_bytes());\n            }\n            PgCube::ZeroVolume(values) => {\n                buff.extend(values.iter().flat_map(|v| v.to_be_bytes()));\n            }\n            PgCube::OneDimensionInterval(x, y) => {\n                buff.extend_from_slice(&x.to_be_bytes());\n                buff.extend_from_slice(&y.to_be_bytes());\n            }\n            PgCube::MultiDimension(multi_values) => {\n                if multi_values.len() != 2 {\n                    return Err(format!(\"invalid CUBE value: {self:?}\"));\n                }\n\n                buff.extend(\n                    multi_values\n                        .iter()\n                        .flat_map(|point| point.iter().flat_map(|scalar| scalar.to_be_bytes())),\n                );\n            }\n        };\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\nfn read_vec(bytes: &mut &[u8]) -> Result<Vec<f64>, String> {\n    if bytes.len() % BYTE_WIDTH != 0 {\n        return Err(format!(\n            \"data length not divisible by {BYTE_WIDTH}: {}\",\n            bytes.len()\n        ));\n    }\n\n    let mut out = Vec::with_capacity(bytes.len() / BYTE_WIDTH);\n\n    while bytes.has_remaining() {\n        out.push(bytes.get_f64());\n    }\n\n    Ok(out)\n}\n\nfn read_cube(header: &Header, mut bytes: &[u8]) -> Result<Vec<Vec<f64>>, String> {\n    if bytes.len() != header.data_size() {\n        return Err(format!(\n            \"expected {} bytes, got {}\",\n            header.data_size(),\n            bytes.len()\n        ));\n    }\n\n    let mut out = Vec::with_capacity(2);\n\n    // Expecting exactly 2 N-dimensional points\n    for _ in 0..2 {\n        let mut point = Vec::new();\n\n        for _ in 0..header.dimensions {\n            point.push(bytes.get_f64());\n        }\n\n        out.push(point);\n    }\n\n    Ok(out)\n}\n\nfn parse_float_from_str(s: &str, error_msg: &str) -> Result<f64, Error> {\n    s.parse().map_err(|_| Error::Decode(error_msg.into()))\n}\n\nfn parse_point(str: &str) -> Result<PgCube, Error> {\n    Ok(PgCube::Point(parse_float_from_str(\n        str,\n        \"Failed to parse point\",\n    )?))\n}\n\nfn parse_zero_volume(content: &str) -> Result<PgCube, Error> {\n    content\n        .split(',')\n        .map(|p| parse_float_from_str(p, \"Failed to parse into zero-volume cube\"))\n        .collect::<Result<Vec<_>, _>>()\n        .map(PgCube::ZeroVolume)\n}\n\nfn parse_one_dimensional_interval(point_vecs: Vec<&str>) -> Result<PgCube, Error> {\n    let x = parse_float_from_str(\n        &remove_parentheses(point_vecs.first().ok_or(Error::Decode(\n            format!(\"Could not decode cube interval x: {:?}\", point_vecs).into(),\n        ))?),\n        \"Failed to parse X in one-dimensional interval\",\n    )?;\n    let y = parse_float_from_str(\n        &remove_parentheses(point_vecs.get(1).ok_or(Error::Decode(\n            format!(\"Could not decode cube interval y: {:?}\", point_vecs).into(),\n        ))?),\n        \"Failed to parse Y in one-dimensional interval\",\n    )?;\n    Ok(PgCube::OneDimensionInterval(x, y))\n}\n\nfn parse_multidimensional_interval(point_vecs: Vec<&str>) -> Result<PgCube, Error> {\n    point_vecs\n        .iter()\n        .map(|&point_vec| {\n            point_vec\n                .split(',')\n                .map(|point| {\n                    parse_float_from_str(\n                        &remove_parentheses(point),\n                        \"Failed to parse into multi-dimension cube\",\n                    )\n                })\n                .collect::<Result<Vec<_>, _>>()\n        })\n        .collect::<Result<Vec<_>, _>>()\n        .map(PgCube::MultiDimension)\n}\n\nfn remove_parentheses(s: &str) -> String {\n    s.trim_matches(|c| c == '(' || c == ')').to_string()\n}\n\nimpl Header {\n    const PACKED_WIDTH: usize = mem::size_of::<u32>();\n\n    fn encoded_size(&self) -> usize {\n        Self::PACKED_WIDTH + self.data_size()\n    }\n\n    fn data_size(&self) -> usize {\n        if self.is_point {\n            self.dimensions * BYTE_WIDTH\n        } else {\n            self.dimensions * BYTE_WIDTH * 2\n        }\n    }\n\n    fn try_write(&self, buff: &mut PgArgumentBuffer) -> Result<(), String> {\n        if self.dimensions > MAX_DIMENSIONS {\n            return Err(format!(\n                \"CUBE dimensionality exceeds allowed maximum ({} > {MAX_DIMENSIONS})\",\n                self.dimensions\n            ));\n        }\n\n        // Cannot overflow thanks to the above check.\n        #[allow(clippy::cast_possible_truncation)]\n        let mut packed = self.dimensions as u32;\n\n        // https://github.com/postgres/postgres/blob/e3ec9dc1bf4983fcedb6f43c71ea12ee26aefc7a/contrib/cube/cubedata.h#L18-L24\n        if self.is_point {\n            packed |= IS_POINT_FLAG;\n        }\n\n        buff.extend(packed.to_be_bytes());\n\n        Ok(())\n    }\n\n    fn try_read(buf: &mut &[u8]) -> Result<Self, String> {\n        if buf.len() < Self::PACKED_WIDTH {\n            return Err(format!(\n                \"expected CUBE data to contain at least {} bytes, got {}\",\n                Self::PACKED_WIDTH,\n                buf.len()\n            ));\n        }\n\n        let packed = buf.get_u32();\n\n        let is_point = packed & IS_POINT_FLAG != 0;\n        let dimensions = packed & !IS_POINT_FLAG;\n\n        // can only overflow on 16-bit platforms\n        let dimensions = usize::try_from(dimensions)\n            .ok()\n            .filter(|&it| it <= MAX_DIMENSIONS)\n            .ok_or_else(|| format!(\"received CUBE data with higher than expected dimensionality: {dimensions} (is_point: {is_point})\"))?;\n\n        Ok(Self {\n            is_point,\n            dimensions,\n        })\n    }\n}\n\nimpl DecodeError {\n    fn new(header: &Header, message: String) -> Self {\n        DecodeError {\n            is_point: header.is_point,\n            dimensions: header.dimensions,\n            message,\n        }\n    }\n}\n\n#[cfg(test)]\nmod cube_tests {\n\n    use std::str::FromStr;\n\n    use super::PgCube;\n\n    const POINT_BYTES: &[u8] = &[128, 0, 0, 1, 64, 0, 0, 0, 0, 0, 0, 0];\n    const ZERO_VOLUME_BYTES: &[u8] = &[\n        128, 0, 0, 2, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0,\n    ];\n    const ONE_DIMENSIONAL_INTERVAL_BYTES: &[u8] = &[\n        0, 0, 0, 1, 64, 28, 0, 0, 0, 0, 0, 0, 64, 32, 0, 0, 0, 0, 0, 0,\n    ];\n    const MULTI_DIMENSION_2_DIM_BYTES: &[u8] = &[\n        0, 0, 0, 2, 63, 240, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0,\n        64, 16, 0, 0, 0, 0, 0, 0,\n    ];\n    const MULTI_DIMENSION_3_DIM_BYTES: &[u8] = &[\n        0, 0, 0, 3, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0, 64, 16, 0, 0, 0, 0, 0, 0, 64,\n        20, 0, 0, 0, 0, 0, 0, 64, 24, 0, 0, 0, 0, 0, 0, 64, 28, 0, 0, 0, 0, 0, 0,\n    ];\n\n    #[test]\n    fn can_deserialise_point_type_byes() {\n        let cube = PgCube::from_bytes(POINT_BYTES).unwrap();\n        assert_eq!(cube, PgCube::Point(2.))\n    }\n\n    #[test]\n    fn can_deserialise_point_type_str() {\n        let cube_1 = PgCube::from_str(\"(2)\").unwrap();\n        assert_eq!(cube_1, PgCube::Point(2.));\n        let cube_2 = PgCube::from_str(\"2\").unwrap();\n        assert_eq!(cube_2, PgCube::Point(2.));\n    }\n\n    #[test]\n    fn can_serialise_point_type() {\n        assert_eq!(PgCube::Point(2.).serialize_to_vec(), POINT_BYTES,)\n    }\n    #[test]\n    fn can_deserialise_zero_volume_bytes() {\n        let cube = PgCube::from_bytes(ZERO_VOLUME_BYTES).unwrap();\n        assert_eq!(cube, PgCube::ZeroVolume(vec![2., 3.]));\n    }\n\n    #[test]\n    fn can_deserialise_zero_volume_string() {\n        let cube_1 = PgCube::from_str(\"(2,3,4)\").unwrap();\n        assert_eq!(cube_1, PgCube::ZeroVolume(vec![2., 3., 4.]));\n        let cube_2 = PgCube::from_str(\"2,3,4\").unwrap();\n        assert_eq!(cube_2, PgCube::ZeroVolume(vec![2., 3., 4.]));\n    }\n\n    #[test]\n    fn can_serialise_zero_volume() {\n        assert_eq!(\n            PgCube::ZeroVolume(vec![2., 3.]).serialize_to_vec(),\n            ZERO_VOLUME_BYTES\n        );\n    }\n\n    #[test]\n    fn can_deserialise_one_dimension_interval_bytes() {\n        let cube = PgCube::from_bytes(ONE_DIMENSIONAL_INTERVAL_BYTES).unwrap();\n        assert_eq!(cube, PgCube::OneDimensionInterval(7., 8.))\n    }\n\n    #[test]\n    fn can_deserialise_one_dimension_interval_string() {\n        let cube_1 = PgCube::from_str(\"((7),(8))\").unwrap();\n        assert_eq!(cube_1, PgCube::OneDimensionInterval(7., 8.));\n        let cube_2 = PgCube::from_str(\"(7),(8)\").unwrap();\n        assert_eq!(cube_2, PgCube::OneDimensionInterval(7., 8.));\n    }\n\n    #[test]\n    fn can_serialise_one_dimension_interval() {\n        assert_eq!(\n            PgCube::OneDimensionInterval(7., 8.).serialize_to_vec(),\n            ONE_DIMENSIONAL_INTERVAL_BYTES\n        )\n    }\n\n    #[test]\n    fn can_deserialise_multi_dimension_2_dimension_byte() {\n        let cube = PgCube::from_bytes(MULTI_DIMENSION_2_DIM_BYTES).unwrap();\n        assert_eq!(\n            cube,\n            PgCube::MultiDimension(vec![vec![1., 2.], vec![3., 4.]])\n        )\n    }\n\n    #[test]\n    fn can_deserialise_multi_dimension_2_dimension_string() {\n        let cube_1 = PgCube::from_str(\"((1,2),(3,4))\").unwrap();\n        assert_eq!(\n            cube_1,\n            PgCube::MultiDimension(vec![vec![1., 2.], vec![3., 4.]])\n        );\n        let cube_2 = PgCube::from_str(\"((1, 2), (3, 4))\").unwrap();\n        assert_eq!(\n            cube_2,\n            PgCube::MultiDimension(vec![vec![1., 2.], vec![3., 4.]])\n        );\n        let cube_3 = PgCube::from_str(\"(1,2),(3,4)\").unwrap();\n        assert_eq!(\n            cube_3,\n            PgCube::MultiDimension(vec![vec![1., 2.], vec![3., 4.]])\n        );\n        let cube_4 = PgCube::from_str(\"(1, 2), (3, 4)\").unwrap();\n        assert_eq!(\n            cube_4,\n            PgCube::MultiDimension(vec![vec![1., 2.], vec![3., 4.]])\n        )\n    }\n\n    #[test]\n    fn can_serialise_multi_dimension_2_dimension() {\n        assert_eq!(\n            PgCube::MultiDimension(vec![vec![1., 2.], vec![3., 4.]]).serialize_to_vec(),\n            MULTI_DIMENSION_2_DIM_BYTES\n        )\n    }\n\n    #[test]\n    fn can_deserialise_multi_dimension_3_dimension_bytes() {\n        let cube = PgCube::from_bytes(MULTI_DIMENSION_3_DIM_BYTES).unwrap();\n        assert_eq!(\n            cube,\n            PgCube::MultiDimension(vec![vec![2., 3., 4.], vec![5., 6., 7.]])\n        )\n    }\n\n    #[test]\n    fn can_deserialise_multi_dimension_3_dimension_string() {\n        let cube = PgCube::from_str(\"((2,3,4),(5,6,7))\").unwrap();\n        assert_eq!(\n            cube,\n            PgCube::MultiDimension(vec![vec![2., 3., 4.], vec![5., 6., 7.]])\n        );\n        let cube_2 = PgCube::from_str(\"(2,3,4),(5,6,7)\").unwrap();\n        assert_eq!(\n            cube_2,\n            PgCube::MultiDimension(vec![vec![2., 3., 4.], vec![5., 6., 7.]])\n        );\n    }\n\n    #[test]\n    fn can_serialise_multi_dimension_3_dimension() {\n        assert_eq!(\n            PgCube::MultiDimension(vec![vec![2., 3., 4.], vec![5., 6., 7.]]).serialize_to_vec(),\n            MULTI_DIMENSION_3_DIM_BYTES\n        )\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/float.rs",
    "content": "use byteorder::{BigEndian, ByteOrder};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl Type<Postgres> for f32 {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::FLOAT4\n    }\n}\n\nimpl PgHasArrayType for f32 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::FLOAT4_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for f32 {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for f32 {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => BigEndian::read_f32(value.as_bytes()?),\n            PgValueFormat::Text => value.as_str()?.parse()?,\n        })\n    }\n}\n\nimpl Type<Postgres> for f64 {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::FLOAT8\n    }\n}\n\nimpl PgHasArrayType for f64 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::FLOAT8_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for f64 {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for f64 {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => BigEndian::read_f64(value.as_bytes()?),\n            PgValueFormat::Text => value.as_str()?.parse()?,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/box.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse std::str::FromStr;\n\nconst ERROR: &str = \"error decoding BOX\";\n\n/// ## Postgres Geometric Box type\n///\n/// Description: Rectangular box\n/// Representation: `((upper_right_x,upper_right_y),(lower_left_x,lower_left_y))`\n///\n/// Boxes are represented by pairs of points that are opposite corners of the box. Values of type box are specified using any of the following syntaxes:\n///\n/// ```text\n/// ( ( upper_right_x , upper_right_y ) , ( lower_left_x , lower_left_y ) )\n/// ( upper_right_x , upper_right_y ) , ( lower_left_x , lower_left_y )\n///   upper_right_x , upper_right_y   ,   lower_left_x , lower_left_y\n/// ```\n/// where `(upper_right_x,upper_right_y) and (lower_left_x,lower_left_y)` are any two opposite corners of the box.\n/// Any two opposite corners can be supplied on input, but the values will be reordered as needed to store the upper right and lower left corners, in that order.\n///\n/// See [Postgres Manual, Section 8.8.4: Geometric Types - Boxes][PG.S.8.8.4] for details.\n///\n/// [PG.S.8.8.4]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-GEOMETRIC-BOXES\n///\n#[derive(Debug, Clone, PartialEq)]\npub struct PgBox {\n    pub upper_right_x: f64,\n    pub upper_right_y: f64,\n    pub lower_left_x: f64,\n    pub lower_left_y: f64,\n}\n\nimpl Type<Postgres> for PgBox {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"box\")\n    }\n}\n\nimpl PgHasArrayType for PgBox {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_box\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgBox {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgBox::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgBox::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgBox {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"box\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl FromStr for PgBox {\n    type Err = BoxDynError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let sanitised = s.replace(['(', ')', '[', ']', ' '], \"\");\n        let mut parts = sanitised.split(',');\n\n        let upper_right_x = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get upper_right_x from {}\", ERROR, s))?;\n\n        let upper_right_y = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get upper_right_y from {}\", ERROR, s))?;\n\n        let lower_left_x = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get lower_left_x from {}\", ERROR, s))?;\n\n        let lower_left_y = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get lower_left_y from {}\", ERROR, s))?;\n\n        if parts.next().is_some() {\n            return Err(format!(\"{}: too many numbers inputted in {}\", ERROR, s).into());\n        }\n\n        Ok(PgBox {\n            upper_right_x,\n            upper_right_y,\n            lower_left_x,\n            lower_left_y,\n        })\n    }\n}\n\nimpl PgBox {\n    fn from_bytes(mut bytes: &[u8]) -> Result<PgBox, BoxDynError> {\n        let upper_right_x = bytes.get_f64();\n        let upper_right_y = bytes.get_f64();\n        let lower_left_x = bytes.get_f64();\n        let lower_left_y = bytes.get_f64();\n\n        Ok(PgBox {\n            upper_right_x,\n            upper_right_y,\n            lower_left_x,\n            lower_left_y,\n        })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), String> {\n        let min_x = &self.upper_right_x.min(self.lower_left_x);\n        let min_y = &self.upper_right_y.min(self.lower_left_y);\n        let max_x = &self.upper_right_x.max(self.lower_left_x);\n        let max_y = &self.upper_right_y.max(self.lower_left_y);\n\n        buff.extend_from_slice(&max_x.to_be_bytes());\n        buff.extend_from_slice(&max_y.to_be_bytes());\n        buff.extend_from_slice(&min_x.to_be_bytes());\n        buff.extend_from_slice(&min_y.to_be_bytes());\n\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\n#[cfg(test)]\nmod box_tests {\n\n    use std::str::FromStr;\n\n    use super::PgBox;\n\n    const BOX_BYTES: &[u8] = &[\n        64, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0,\n        0, 0, 0, 0,\n    ];\n\n    #[test]\n    fn can_deserialise_box_type_bytes_in_order() {\n        let pg_box = PgBox::from_bytes(BOX_BYTES).unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 2.,\n                upper_right_y: 2.,\n                lower_left_x: -2.,\n                lower_left_y: -2.\n            }\n        )\n    }\n\n    #[test]\n    fn can_deserialise_box_type_str_first_syntax() {\n        let pg_box = PgBox::from_str(\"[( 1, 2), (3, 4 )]\").unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 1.,\n                upper_right_y: 2.,\n                lower_left_x: 3.,\n                lower_left_y: 4.\n            }\n        );\n    }\n    #[test]\n    fn can_deserialise_box_type_str_second_syntax() {\n        let pg_box = PgBox::from_str(\"(( 1, 2), (3, 4 ))\").unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 1.,\n                upper_right_y: 2.,\n                lower_left_x: 3.,\n                lower_left_y: 4.\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_box_type_str_third_syntax() {\n        let pg_box = PgBox::from_str(\"(1, 2), (3, 4 )\").unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 1.,\n                upper_right_y: 2.,\n                lower_left_x: 3.,\n                lower_left_y: 4.\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_box_type_str_fourth_syntax() {\n        let pg_box = PgBox::from_str(\"1, 2, 3, 4\").unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 1.,\n                upper_right_y: 2.,\n                lower_left_x: 3.,\n                lower_left_y: 4.\n            }\n        );\n    }\n\n    #[test]\n    fn cannot_deserialise_too_many_numbers() {\n        let input_str = \"1, 2, 3, 4, 5\";\n        let pg_box = PgBox::from_str(input_str);\n        assert!(pg_box.is_err());\n        if let Err(err) = pg_box {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding BOX: too many numbers inputted in {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn cannot_deserialise_too_few_numbers() {\n        let input_str = \"1, 2, 3 \";\n        let pg_box = PgBox::from_str(input_str);\n        assert!(pg_box.is_err());\n        if let Err(err) = pg_box {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding BOX: could not get lower_left_y from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn cannot_deserialise_invalid_numbers() {\n        let input_str = \"1, 2, 3, FOUR\";\n        let pg_box = PgBox::from_str(input_str);\n        assert!(pg_box.is_err());\n        if let Err(err) = pg_box {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding BOX: could not get lower_left_y from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_box_type_str_float() {\n        let pg_box = PgBox::from_str(\"(1.1, 2.2), (3.3, 4.4)\").unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 1.1,\n                upper_right_y: 2.2,\n                lower_left_x: 3.3,\n                lower_left_y: 4.4\n            }\n        );\n    }\n\n    #[test]\n    fn can_serialise_box_type_in_order() {\n        let pg_box = PgBox {\n            upper_right_x: 2.,\n            lower_left_x: -2.,\n            upper_right_y: -2.,\n            lower_left_y: 2.,\n        };\n        assert_eq!(pg_box.serialize_to_vec(), BOX_BYTES,)\n    }\n\n    #[test]\n    fn can_serialise_box_type_out_of_order() {\n        let pg_box = PgBox {\n            upper_right_x: -2.,\n            lower_left_x: 2.,\n            upper_right_y: 2.,\n            lower_left_y: -2.,\n        };\n        assert_eq!(pg_box.serialize_to_vec(), BOX_BYTES,)\n    }\n\n    #[test]\n    fn can_order_box() {\n        let pg_box = PgBox {\n            upper_right_x: -2.,\n            lower_left_x: 2.,\n            upper_right_y: 2.,\n            lower_left_y: -2.,\n        };\n        let bytes = pg_box.serialize_to_vec();\n\n        let pg_box = PgBox::from_bytes(&bytes).unwrap();\n        assert_eq!(\n            pg_box,\n            PgBox {\n                upper_right_x: 2.,\n                upper_right_y: 2.,\n                lower_left_x: -2.,\n                lower_left_y: -2.\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/circle.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse sqlx_core::Error;\nuse std::str::FromStr;\n\nconst ERROR: &str = \"error decoding CIRCLE\";\n\n/// ## Postgres Geometric Circle type\n///\n/// Description: Circle\n/// Representation: `< (x, y), radius >` (center point and radius)\n///\n/// ```text\n/// < ( x , y ) , radius >\n/// ( ( x , y ) , radius )\n///   ( x , y ) , radius\n///     x , y   , radius\n/// ```\n/// where `(x,y)` is the center point.\n///\n/// See [Postgres Manual, Section 8.8.7, Geometric Types - Circles][PG.S.8.8.7] for details.\n///\n/// [PG.S.8.8.7]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-CIRCLE\n///\n#[derive(Debug, Clone, PartialEq)]\npub struct PgCircle {\n    pub x: f64,\n    pub y: f64,\n    pub radius: f64,\n}\n\nimpl Type<Postgres> for PgCircle {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"circle\")\n    }\n}\n\nimpl PgHasArrayType for PgCircle {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_circle\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgCircle {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgCircle::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgCircle::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgCircle {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"circle\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl FromStr for PgCircle {\n    type Err = BoxDynError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let sanitised = s.replace(['<', '>', '(', ')', ' '], \"\");\n        let mut parts = sanitised.split(',');\n\n        let x = parts\n            .next()\n            .and_then(|s| s.trim().parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get x from {}\", ERROR, s))?;\n\n        let y = parts\n            .next()\n            .and_then(|s| s.trim().parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get y from {}\", ERROR, s))?;\n\n        let radius = parts\n            .next()\n            .and_then(|s| s.trim().parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get radius from {}\", ERROR, s))?;\n\n        if parts.next().is_some() {\n            return Err(format!(\"{}: too many numbers inputted in {}\", ERROR, s).into());\n        }\n\n        if radius < 0. {\n            return Err(format!(\"{}: cannot have negative radius: {}\", ERROR, s).into());\n        }\n\n        Ok(PgCircle { x, y, radius })\n    }\n}\n\nimpl PgCircle {\n    fn from_bytes(mut bytes: &[u8]) -> Result<PgCircle, Error> {\n        let x = bytes.get_f64();\n        let y = bytes.get_f64();\n        let r = bytes.get_f64();\n        Ok(PgCircle { x, y, radius: r })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), Error> {\n        buff.extend_from_slice(&self.x.to_be_bytes());\n        buff.extend_from_slice(&self.y.to_be_bytes());\n        buff.extend_from_slice(&self.radius.to_be_bytes());\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\n#[cfg(test)]\nmod circle_tests {\n\n    use std::str::FromStr;\n\n    use super::PgCircle;\n\n    const CIRCLE_BYTES: &[u8] = &[\n        63, 241, 153, 153, 153, 153, 153, 154, 64, 1, 153, 153, 153, 153, 153, 154, 64, 10, 102,\n        102, 102, 102, 102, 102,\n    ];\n\n    #[test]\n    fn can_deserialise_circle_type_bytes() {\n        let circle = PgCircle::from_bytes(CIRCLE_BYTES).unwrap();\n        assert_eq!(\n            circle,\n            PgCircle {\n                x: 1.1,\n                y: 2.2,\n                radius: 3.3\n            }\n        )\n    }\n\n    #[test]\n    fn can_deserialise_circle_type_str() {\n        let circle = PgCircle::from_str(\"<(1, 2), 3 >\").unwrap();\n        assert_eq!(\n            circle,\n            PgCircle {\n                x: 1.0,\n                y: 2.0,\n                radius: 3.0\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_circle_type_str_second_syntax() {\n        let circle = PgCircle::from_str(\"((1, 2), 3 )\").unwrap();\n        assert_eq!(\n            circle,\n            PgCircle {\n                x: 1.0,\n                y: 2.0,\n                radius: 3.0\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_circle_type_str_third_syntax() {\n        let circle = PgCircle::from_str(\"(1, 2), 3 \").unwrap();\n        assert_eq!(\n            circle,\n            PgCircle {\n                x: 1.0,\n                y: 2.0,\n                radius: 3.0\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_circle_type_str_fourth_syntax() {\n        let circle = PgCircle::from_str(\"1, 2, 3 \").unwrap();\n        assert_eq!(\n            circle,\n            PgCircle {\n                x: 1.0,\n                y: 2.0,\n                radius: 3.0\n            }\n        );\n    }\n\n    #[test]\n    fn cannot_deserialise_circle_invalid_numbers() {\n        let input_str = \"1, 2, Three\";\n        let circle = PgCircle::from_str(input_str);\n        assert!(circle.is_err());\n        if let Err(err) = circle {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding CIRCLE: could not get radius from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn cannot_deserialise_circle_negative_radius() {\n        let input_str = \"1, 2, -3\";\n        let circle = PgCircle::from_str(input_str);\n        assert!(circle.is_err());\n        if let Err(err) = circle {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding CIRCLE: cannot have negative radius: {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_circle_type_str_float() {\n        let circle = PgCircle::from_str(\"<(1.1, 2.2), 3.3>\").unwrap();\n        assert_eq!(\n            circle,\n            PgCircle {\n                x: 1.1,\n                y: 2.2,\n                radius: 3.3\n            }\n        );\n    }\n\n    #[test]\n    fn can_serialise_circle_type() {\n        let circle = PgCircle {\n            x: 1.1,\n            y: 2.2,\n            radius: 3.3,\n        };\n        assert_eq!(circle.serialize_to_vec(), CIRCLE_BYTES,)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/line.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse std::str::FromStr;\n\nconst ERROR: &str = \"error decoding LINE\";\n\n/// ## Postgres Geometric Line type\n///\n/// Description: Infinite line\n/// Representation: `{A, B, C}`\n///\n/// Lines are represented by the linear equation Ax + By + C = 0, where A and B are not both zero.\n///\n/// See [Postgres Manual, Section 8.8.2, Geometric Types - Lines][PG.S.8.8.2] for details.\n///\n/// [PG.S.8.8.2]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-LINE\n///\n#[derive(Debug, Clone, PartialEq)]\npub struct PgLine {\n    pub a: f64,\n    pub b: f64,\n    pub c: f64,\n}\n\nimpl Type<Postgres> for PgLine {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"line\")\n    }\n}\n\nimpl PgHasArrayType for PgLine {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_line\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgLine {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgLine::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgLine::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgLine {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"line\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl FromStr for PgLine {\n    type Err = BoxDynError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let mut parts = s\n            .trim_matches(|c| c == '{' || c == '}' || c == ' ')\n            .split(',');\n\n        let a = parts\n            .next()\n            .and_then(|s| s.trim().parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get a from {}\", ERROR, s))?;\n\n        let b = parts\n            .next()\n            .and_then(|s| s.trim().parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get b from {}\", ERROR, s))?;\n\n        let c = parts\n            .next()\n            .and_then(|s| s.trim().parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get c from {}\", ERROR, s))?;\n\n        if parts.next().is_some() {\n            return Err(format!(\"{}: too many numbers inputted in {}\", ERROR, s).into());\n        }\n\n        Ok(PgLine { a, b, c })\n    }\n}\n\nimpl PgLine {\n    fn from_bytes(mut bytes: &[u8]) -> Result<PgLine, BoxDynError> {\n        let a = bytes.get_f64();\n        let b = bytes.get_f64();\n        let c = bytes.get_f64();\n        Ok(PgLine { a, b, c })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {\n        buff.extend_from_slice(&self.a.to_be_bytes());\n        buff.extend_from_slice(&self.b.to_be_bytes());\n        buff.extend_from_slice(&self.c.to_be_bytes());\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\n#[cfg(test)]\nmod line_tests {\n\n    use std::str::FromStr;\n\n    use super::PgLine;\n\n    const LINE_BYTES: &[u8] = &[\n        63, 241, 153, 153, 153, 153, 153, 154, 64, 1, 153, 153, 153, 153, 153, 154, 64, 10, 102,\n        102, 102, 102, 102, 102,\n    ];\n\n    #[test]\n    fn can_deserialise_line_type_bytes() {\n        let line = PgLine::from_bytes(LINE_BYTES).unwrap();\n        assert_eq!(\n            line,\n            PgLine {\n                a: 1.1,\n                b: 2.2,\n                c: 3.3\n            }\n        )\n    }\n\n    #[test]\n    fn can_deserialise_line_type_str() {\n        let line = PgLine::from_str(\"{ 1, 2, 3 }\").unwrap();\n        assert_eq!(\n            line,\n            PgLine {\n                a: 1.0,\n                b: 2.0,\n                c: 3.0\n            }\n        );\n    }\n\n    #[test]\n    fn cannot_deserialise_line_too_few_numbers() {\n        let input_str = \"{ 1, 2 }\";\n        let line = PgLine::from_str(input_str);\n        assert!(line.is_err());\n        if let Err(err) = line {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding LINE: could not get c from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn cannot_deserialise_line_too_many_numbers() {\n        let input_str = \"{ 1, 2, 3, 4 }\";\n        let line = PgLine::from_str(input_str);\n        assert!(line.is_err());\n        if let Err(err) = line {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding LINE: too many numbers inputted in {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn cannot_deserialise_line_invalid_numbers() {\n        let input_str = \"{ 1, 2, three }\";\n        let line = PgLine::from_str(input_str);\n        assert!(line.is_err());\n        if let Err(err) = line {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding LINE: could not get c from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_line_type_str_float() {\n        let line = PgLine::from_str(\"{1.1, 2.2, 3.3}\").unwrap();\n        assert_eq!(\n            line,\n            PgLine {\n                a: 1.1,\n                b: 2.2,\n                c: 3.3\n            }\n        );\n    }\n\n    #[test]\n    fn can_serialise_line_type() {\n        let line = PgLine {\n            a: 1.1,\n            b: 2.2,\n            c: 3.3,\n        };\n        assert_eq!(line.serialize_to_vec(), LINE_BYTES,)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/line_segment.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse std::str::FromStr;\n\nconst ERROR: &str = \"error decoding LSEG\";\n\n/// ## Postgres Geometric Line Segment type\n///\n/// Description: Finite line segment\n/// Representation: `((start_x,start_y),(end_x,end_y))`\n///\n///\n/// Line segments are represented by pairs of points that are the endpoints of the segment. Values of type lseg are specified using any of the following syntaxes:\n/// ```text\n/// [ ( start_x , start_y ) , ( end_x , end_y ) ]\n/// ( ( start_x , start_y ) , ( end_x , end_y ) )\n///   ( start_x , start_y ) , ( end_x , end_y )\n///     start_x , start_y   ,   end_x , end_y\n/// ```\n/// where `(start_x,start_y) and (end_x,end_y)` are the end points of the line segment.\n///\n/// See [Postgres Manual, Section 8.8.3, Geometric Types - Line Segments][PG.S.8.8.3] for details.\n///\n/// [PG.S.8.8.3]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-LSEG\n///\n#[doc(alias = \"line segment\")]\n#[derive(Debug, Clone, PartialEq)]\npub struct PgLSeg {\n    pub start_x: f64,\n    pub start_y: f64,\n    pub end_x: f64,\n    pub end_y: f64,\n}\n\nimpl Type<Postgres> for PgLSeg {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"lseg\")\n    }\n}\n\nimpl PgHasArrayType for PgLSeg {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_lseg\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgLSeg {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgLSeg::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgLSeg::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgLSeg {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"lseg\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl FromStr for PgLSeg {\n    type Err = BoxDynError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let sanitised = s.replace(['(', ')', '[', ']', ' '], \"\");\n        let mut parts = sanitised.split(',');\n\n        let start_x = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get start_x from {}\", ERROR, s))?;\n\n        let start_y = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get start_y from {}\", ERROR, s))?;\n\n        let end_x = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get end_x from {}\", ERROR, s))?;\n\n        let end_y = parts\n            .next()\n            .and_then(|s| s.parse::<f64>().ok())\n            .ok_or_else(|| format!(\"{}: could not get end_y from {}\", ERROR, s))?;\n\n        if parts.next().is_some() {\n            return Err(format!(\"{}: too many numbers inputted in {}\", ERROR, s).into());\n        }\n\n        Ok(PgLSeg {\n            start_x,\n            start_y,\n            end_x,\n            end_y,\n        })\n    }\n}\n\nimpl PgLSeg {\n    fn from_bytes(mut bytes: &[u8]) -> Result<PgLSeg, BoxDynError> {\n        let start_x = bytes.get_f64();\n        let start_y = bytes.get_f64();\n        let end_x = bytes.get_f64();\n        let end_y = bytes.get_f64();\n\n        Ok(PgLSeg {\n            start_x,\n            start_y,\n            end_x,\n            end_y,\n        })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {\n        buff.extend_from_slice(&self.start_x.to_be_bytes());\n        buff.extend_from_slice(&self.start_y.to_be_bytes());\n        buff.extend_from_slice(&self.end_x.to_be_bytes());\n        buff.extend_from_slice(&self.end_y.to_be_bytes());\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\n#[cfg(test)]\nmod lseg_tests {\n\n    use std::str::FromStr;\n\n    use super::PgLSeg;\n\n    const LINE_SEGMENT_BYTES: &[u8] = &[\n        63, 241, 153, 153, 153, 153, 153, 154, 64, 1, 153, 153, 153, 153, 153, 154, 64, 10, 102,\n        102, 102, 102, 102, 102, 64, 17, 153, 153, 153, 153, 153, 154,\n    ];\n\n    #[test]\n    fn can_deserialise_lseg_type_bytes() {\n        let lseg = PgLSeg::from_bytes(LINE_SEGMENT_BYTES).unwrap();\n        assert_eq!(\n            lseg,\n            PgLSeg {\n                start_x: 1.1,\n                start_y: 2.2,\n                end_x: 3.3,\n                end_y: 4.4\n            }\n        )\n    }\n\n    #[test]\n    fn can_deserialise_lseg_type_str_first_syntax() {\n        let lseg = PgLSeg::from_str(\"[( 1, 2), (3, 4 )]\").unwrap();\n        assert_eq!(\n            lseg,\n            PgLSeg {\n                start_x: 1.,\n                start_y: 2.,\n                end_x: 3.,\n                end_y: 4.\n            }\n        );\n    }\n    #[test]\n    fn can_deserialise_lseg_type_str_second_syntax() {\n        let lseg = PgLSeg::from_str(\"(( 1, 2), (3, 4 ))\").unwrap();\n        assert_eq!(\n            lseg,\n            PgLSeg {\n                start_x: 1.,\n                start_y: 2.,\n                end_x: 3.,\n                end_y: 4.\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_lseg_type_str_third_syntax() {\n        let lseg = PgLSeg::from_str(\"(1, 2), (3, 4 )\").unwrap();\n        assert_eq!(\n            lseg,\n            PgLSeg {\n                start_x: 1.,\n                start_y: 2.,\n                end_x: 3.,\n                end_y: 4.\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_lseg_type_str_fourth_syntax() {\n        let lseg = PgLSeg::from_str(\"1, 2, 3, 4\").unwrap();\n        assert_eq!(\n            lseg,\n            PgLSeg {\n                start_x: 1.,\n                start_y: 2.,\n                end_x: 3.,\n                end_y: 4.\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_too_many_numbers() {\n        let input_str = \"1, 2, 3, 4, 5\";\n        let lseg = PgLSeg::from_str(input_str);\n        assert!(lseg.is_err());\n        if let Err(err) = lseg {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding LSEG: too many numbers inputted in {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_too_few_numbers() {\n        let input_str = \"1, 2, 3\";\n        let lseg = PgLSeg::from_str(input_str);\n        assert!(lseg.is_err());\n        if let Err(err) = lseg {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding LSEG: could not get end_y from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_invalid_numbers() {\n        let input_str = \"1, 2, 3, FOUR\";\n        let lseg = PgLSeg::from_str(input_str);\n        assert!(lseg.is_err());\n        if let Err(err) = lseg {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error decoding LSEG: could not get end_y from {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_lseg_type_str_float() {\n        let lseg = PgLSeg::from_str(\"(1.1, 2.2), (3.3, 4.4)\").unwrap();\n        assert_eq!(\n            lseg,\n            PgLSeg {\n                start_x: 1.1,\n                start_y: 2.2,\n                end_x: 3.3,\n                end_y: 4.4\n            }\n        );\n    }\n\n    #[test]\n    fn can_serialise_lseg_type() {\n        let lseg = PgLSeg {\n            start_x: 1.1,\n            start_y: 2.2,\n            end_x: 3.3,\n            end_y: 4.4,\n        };\n        assert_eq!(lseg.serialize_to_vec(), LINE_SEGMENT_BYTES,)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/mod.rs",
    "content": "pub mod r#box;\npub mod circle;\npub mod line;\npub mod line_segment;\npub mod path;\npub mod point;\npub mod polygon;\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/path.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::{PgPoint, Type};\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse sqlx_core::Error;\nuse std::mem;\nuse std::str::FromStr;\n\nconst BYTE_WIDTH: usize = mem::size_of::<f64>();\n\n/// ## Postgres Geometric Path type\n///\n/// Description: Open path or Closed path (similar to polygon)\n/// Representation: Open `[(x1,y1),...]`, Closed `((x1,y1),...)`\n///\n/// Paths are represented by lists of connected points. Paths can be open, where the first and last points in the list are considered not connected, or closed, where the first and last points are considered connected.\n/// Values of type path are specified using any of the following syntaxes:\n/// ```text\n/// [ ( x1 , y1 ) , ... , ( xn , yn ) ]\n/// ( ( x1 , y1 ) , ... , ( xn , yn ) )\n///   ( x1 , y1 ) , ... , ( xn , yn )\n///   ( x1 , y1   , ... ,   xn , yn )\n///     x1 , y1   , ... ,   xn , yn\n/// ```\n/// where the points are the end points of the line segments comprising the path. Square brackets `([])` indicate an open path, while parentheses `(())` indicate a closed path.\n/// When the outermost parentheses are omitted, as in the third through fifth syntaxes, a closed path is assumed.\n///\n/// See [Postgres Manual, Section 8.8.5, Geometric Types - Paths][PG.S.8.8.5] for details.\n///\n/// [PG.S.8.8.5]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-GEOMETRIC-PATHS\n///\n#[derive(Debug, Clone, PartialEq)]\npub struct PgPath {\n    pub closed: bool,\n    pub points: Vec<PgPoint>,\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\nstruct Header {\n    is_closed: bool,\n    length: usize,\n}\n\nimpl Type<Postgres> for PgPath {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"path\")\n    }\n}\n\nimpl PgHasArrayType for PgPath {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_path\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgPath {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgPath::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgPath::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgPath {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"path\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl FromStr for PgPath {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let closed = !s.contains('[');\n        let sanitised = s.replace(['(', ')', '[', ']', ' '], \"\");\n        let parts = sanitised.split(',').collect::<Vec<_>>();\n\n        let mut points = vec![];\n\n        if parts.len() % 2 != 0 {\n            return Err(Error::Decode(\n                format!(\"Unmatched pair in PATH: {}\", s).into(),\n            ));\n        }\n\n        for chunk in parts.chunks_exact(2) {\n            if let [x_str, y_str] = chunk {\n                let x = parse_float_from_str(x_str, \"could not get x\")?;\n                let y = parse_float_from_str(y_str, \"could not get y\")?;\n\n                let point = PgPoint { x, y };\n                points.push(point);\n            }\n        }\n\n        if !points.is_empty() {\n            return Ok(PgPath { points, closed });\n        }\n\n        Err(Error::Decode(\n            format!(\"could not get path from {}\", s).into(),\n        ))\n    }\n}\n\nimpl PgPath {\n    fn header(&self) -> Header {\n        Header {\n            is_closed: self.closed,\n            length: self.points.len(),\n        }\n    }\n\n    fn from_bytes(mut bytes: &[u8]) -> Result<Self, BoxDynError> {\n        let header = Header::try_read(&mut bytes)?;\n\n        if bytes.len() != header.data_size() {\n            return Err(format!(\n                \"expected {} bytes after header, got {}\",\n                header.data_size(),\n                bytes.len()\n            )\n            .into());\n        }\n\n        if bytes.len() % BYTE_WIDTH * 2 != 0 {\n            return Err(format!(\n                \"data length not divisible by pairs of {BYTE_WIDTH}: {}\",\n                bytes.len()\n            )\n            .into());\n        }\n\n        let mut out_points = Vec::with_capacity(bytes.len() / (BYTE_WIDTH * 2));\n\n        while bytes.has_remaining() {\n            let point = PgPoint {\n                x: bytes.get_f64(),\n                y: bytes.get_f64(),\n            };\n            out_points.push(point)\n        }\n        Ok(PgPath {\n            closed: header.is_closed,\n            points: out_points,\n        })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {\n        let header = self.header();\n        buff.reserve(header.data_size());\n        header.try_write(buff)?;\n\n        for point in &self.points {\n            buff.extend_from_slice(&point.x.to_be_bytes());\n            buff.extend_from_slice(&point.y.to_be_bytes());\n        }\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\nimpl Header {\n    const HEADER_WIDTH: usize = mem::size_of::<i8>() + mem::size_of::<i32>();\n\n    fn data_size(&self) -> usize {\n        self.length * BYTE_WIDTH * 2\n    }\n\n    fn try_read(buf: &mut &[u8]) -> Result<Self, String> {\n        if buf.len() < Self::HEADER_WIDTH {\n            return Err(format!(\n                \"expected PATH data to contain at least {} bytes, got {}\",\n                Self::HEADER_WIDTH,\n                buf.len()\n            ));\n        }\n\n        let is_closed = buf.get_i8();\n        let length = buf.get_i32();\n\n        let length = usize::try_from(length).ok().ok_or_else(|| {\n            format!(\n                \"received PATH data length: {length}. Expected length between 0 and {}\",\n                usize::MAX\n            )\n        })?;\n\n        Ok(Self {\n            is_closed: is_closed != 0,\n            length,\n        })\n    }\n\n    fn try_write(&self, buff: &mut PgArgumentBuffer) -> Result<(), String> {\n        let is_closed = self.is_closed as i8;\n\n        let length = i32::try_from(self.length).map_err(|_| {\n            format!(\n                \"PATH length exceeds allowed maximum ({} > {})\",\n                self.length,\n                i32::MAX\n            )\n        })?;\n\n        buff.extend(is_closed.to_be_bytes());\n        buff.extend(length.to_be_bytes());\n\n        Ok(())\n    }\n}\n\nfn parse_float_from_str(s: &str, error_msg: &str) -> Result<f64, Error> {\n    s.parse().map_err(|_| Error::Decode(error_msg.into()))\n}\n\n#[cfg(test)]\nmod path_tests {\n\n    use std::str::FromStr;\n\n    use crate::types::PgPoint;\n\n    use super::PgPath;\n\n    const PATH_CLOSED_BYTES: &[u8] = &[\n        1, 0, 0, 0, 2, 63, 240, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0,\n        64, 16, 0, 0, 0, 0, 0, 0,\n    ];\n\n    const PATH_OPEN_BYTES: &[u8] = &[\n        0, 0, 0, 0, 2, 63, 240, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0,\n        64, 16, 0, 0, 0, 0, 0, 0,\n    ];\n\n    const PATH_UNEVEN_POINTS: &[u8] = &[\n        0, 0, 0, 0, 2, 63, 240, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0,\n        64, 16, 0, 0,\n    ];\n\n    #[test]\n    fn can_deserialise_path_type_bytes_closed() {\n        let path = PgPath::from_bytes(PATH_CLOSED_BYTES).unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: true,\n                points: vec![PgPoint { x: 1.0, y: 2.0 }, PgPoint { x: 3.0, y: 4.0 }]\n            }\n        )\n    }\n\n    #[test]\n    fn cannot_deserialise_path_type_uneven_point_bytes() {\n        let path = PgPath::from_bytes(PATH_UNEVEN_POINTS);\n        assert!(path.is_err());\n\n        if let Err(err) = path {\n            assert_eq!(\n                err.to_string(),\n                format!(\"expected 32 bytes after header, got 28\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_path_type_bytes_open() {\n        let path = PgPath::from_bytes(PATH_OPEN_BYTES).unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: false,\n                points: vec![PgPoint { x: 1.0, y: 2.0 }, PgPoint { x: 3.0, y: 4.0 }]\n            }\n        )\n    }\n\n    #[test]\n    fn can_deserialise_path_type_str_first_syntax() {\n        let path = PgPath::from_str(\"[( 1, 2), (3, 4 )]\").unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: false,\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn cannot_deserialise_path_type_str_uneven_points_first_syntax() {\n        let input_str = \"[( 1, 2), (3)]\";\n        let path = PgPath::from_str(input_str);\n\n        assert!(path.is_err());\n\n        if let Err(err) = path {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error occurred while decoding: Unmatched pair in PATH: {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_path_type_str_second_syntax() {\n        let path = PgPath::from_str(\"(( 1, 2), (3, 4 ))\").unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: true,\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_path_type_str_third_syntax() {\n        let path = PgPath::from_str(\"(1, 2), (3, 4 )\").unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: true,\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_path_type_str_fourth_syntax() {\n        let path = PgPath::from_str(\"1, 2, 3, 4\").unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: true,\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_path_type_str_float() {\n        let path = PgPath::from_str(\"(1.1, 2.2), (3.3, 4.4)\").unwrap();\n        assert_eq!(\n            path,\n            PgPath {\n                closed: true,\n                points: vec![PgPoint { x: 1.1, y: 2.2 }, PgPoint { x: 3.3, y: 4.4 }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_serialise_path_type() {\n        let path = PgPath {\n            closed: true,\n            points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }],\n        };\n        assert_eq!(path.serialize_to_vec(), PATH_CLOSED_BYTES,)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/point.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse sqlx_core::Error;\nuse std::str::FromStr;\n\n/// ## Postgres Geometric Point type\n///\n/// Description: Point on a plane\n/// Representation: `(x, y)`\n///\n/// Points are the fundamental two-dimensional building block for geometric types. Values of type point are specified using either of the following syntaxes:\n/// ```text\n/// ( x , y )\n///  x , y\n/// ````\n/// where x and y are the respective coordinates, as floating-point numbers.\n///\n/// See [Postgres Manual, Section 8.8.1, Geometric Types - Points][PG.S.8.8.1] for details.\n///\n/// [PG.S.8.8.1]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-GEOMETRIC-POINTS\n///\n#[derive(Debug, Clone, PartialEq)]\npub struct PgPoint {\n    pub x: f64,\n    pub y: f64,\n}\n\nimpl Type<Postgres> for PgPoint {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"point\")\n    }\n}\n\nimpl PgHasArrayType for PgPoint {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_point\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgPoint {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgPoint::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgPoint::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgPoint {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"point\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nfn parse_float_from_str(s: &str, error_msg: &str) -> Result<f64, Error> {\n    s.trim()\n        .parse()\n        .map_err(|_| Error::Decode(error_msg.into()))\n}\n\nimpl FromStr for PgPoint {\n    type Err = BoxDynError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let (x_str, y_str) = s\n            .trim_matches(|c| c == '(' || c == ')' || c == ' ')\n            .split_once(',')\n            .ok_or_else(|| format!(\"error decoding POINT: could not get x and y from {}\", s))?;\n\n        let x = parse_float_from_str(x_str, \"error decoding POINT: could not get x\")?;\n        let y = parse_float_from_str(y_str, \"error decoding POINT: could not get y\")?;\n\n        Ok(PgPoint { x, y })\n    }\n}\n\nimpl PgPoint {\n    fn from_bytes(mut bytes: &[u8]) -> Result<PgPoint, BoxDynError> {\n        let x = bytes.get_f64();\n        let y = bytes.get_f64();\n        Ok(PgPoint { x, y })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {\n        buff.extend_from_slice(&self.x.to_be_bytes());\n        buff.extend_from_slice(&self.y.to_be_bytes());\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\n#[cfg(test)]\nmod point_tests {\n\n    use std::str::FromStr;\n\n    use super::PgPoint;\n\n    const POINT_BYTES: &[u8] = &[\n        64, 0, 204, 204, 204, 204, 204, 205, 64, 20, 204, 204, 204, 204, 204, 205,\n    ];\n\n    #[test]\n    fn can_deserialise_point_type_bytes() {\n        let point = PgPoint::from_bytes(POINT_BYTES).unwrap();\n        assert_eq!(point, PgPoint { x: 2.1, y: 5.2 })\n    }\n\n    #[test]\n    fn can_deserialise_point_type_str() {\n        let point = PgPoint::from_str(\"(2, 3)\").unwrap();\n        assert_eq!(point, PgPoint { x: 2., y: 3. });\n    }\n\n    #[test]\n    fn can_deserialise_point_type_str_float() {\n        let point = PgPoint::from_str(\"(2.5, 3.4)\").unwrap();\n        assert_eq!(point, PgPoint { x: 2.5, y: 3.4 });\n    }\n\n    #[test]\n    fn can_serialise_point_type() {\n        let point = PgPoint { x: 2.1, y: 5.2 };\n        assert_eq!(point.serialize_to_vec(), POINT_BYTES,)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/geometry/polygon.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::{PgPoint, Type};\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse sqlx_core::bytes::Buf;\nuse sqlx_core::Error;\nuse std::mem;\nuse std::str::FromStr;\n\nconst BYTE_WIDTH: usize = mem::size_of::<f64>();\n\n/// ## Postgres Geometric Polygon type\n///\n/// Description: Polygon (similar to closed polygon)\n/// Representation: `((x1,y1),...)`\n///\n/// Polygons are represented by lists of points (the vertices of the polygon). Polygons are very similar to closed paths; the essential semantic difference is that a polygon is considered to include the area within it, while a path is not.\n/// An important implementation difference between polygons and paths is that the stored representation of a polygon includes its smallest bounding box. This speeds up certain search operations, although computing the bounding box adds overhead while constructing new polygons.\n/// Values of type polygon are specified using any of the following syntaxes:\n///\n/// ```text\n/// ( ( x1 , y1 ) , ... , ( xn , yn ) )\n///   ( x1 , y1 ) , ... , ( xn , yn )\n///   ( x1 , y1   , ... ,   xn , yn )\n///     x1 , y1   , ... ,   xn , yn\n/// ```\n///\n/// where the points are the end points of the line segments comprising the boundary of the polygon.\n///\n/// See [Postgres Manual, Section 8.8.6, Geometric Types - Polygons][PG.S.8.8.6] for details.\n///\n/// [PG.S.8.8.6]: https://www.postgresql.org/docs/current/datatype-geometric.html#DATATYPE-POLYGON\n///\n#[derive(Debug, Clone, PartialEq)]\npub struct PgPolygon {\n    pub points: Vec<PgPoint>,\n}\n\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\nstruct Header {\n    length: usize,\n}\n\nimpl Type<Postgres> for PgPolygon {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"polygon\")\n    }\n}\n\nimpl PgHasArrayType for PgPolygon {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_polygon\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgPolygon {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {\n        match value.format() {\n            PgValueFormat::Text => Ok(PgPolygon::from_str(value.as_str()?)?),\n            PgValueFormat::Binary => Ok(PgPolygon::from_bytes(value.as_bytes()?)?),\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgPolygon {\n    fn produces(&self) -> Option<PgTypeInfo> {\n        Some(PgTypeInfo::with_name(\"polygon\"))\n    }\n\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        self.serialize(buf)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl FromStr for PgPolygon {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let sanitised = s.replace(['(', ')', '[', ']', ' '], \"\");\n        let parts = sanitised.split(',').collect::<Vec<_>>();\n\n        let mut points = vec![];\n\n        if parts.len() % 2 != 0 {\n            return Err(Error::Decode(\n                format!(\"Unmatched pair in POLYGON: {}\", s).into(),\n            ));\n        }\n\n        for chunk in parts.chunks_exact(2) {\n            if let [x_str, y_str] = chunk {\n                let x = parse_float_from_str(x_str, \"could not get x\")?;\n                let y = parse_float_from_str(y_str, \"could not get y\")?;\n\n                let point = PgPoint { x, y };\n                points.push(point);\n            }\n        }\n\n        if !points.is_empty() {\n            return Ok(PgPolygon { points });\n        }\n\n        Err(Error::Decode(\n            format!(\"could not get polygon from {}\", s).into(),\n        ))\n    }\n}\n\nimpl PgPolygon {\n    fn header(&self) -> Header {\n        Header {\n            length: self.points.len(),\n        }\n    }\n\n    fn from_bytes(mut bytes: &[u8]) -> Result<Self, BoxDynError> {\n        let header = Header::try_read(&mut bytes)?;\n\n        if bytes.len() != header.data_size() {\n            return Err(format!(\n                \"expected {} bytes after header, got {}\",\n                header.data_size(),\n                bytes.len()\n            )\n            .into());\n        }\n\n        if bytes.len() % BYTE_WIDTH * 2 != 0 {\n            return Err(format!(\n                \"data length not divisible by pairs of {BYTE_WIDTH}: {}\",\n                bytes.len()\n            )\n            .into());\n        }\n\n        let mut out_points = Vec::with_capacity(bytes.len() / (BYTE_WIDTH * 2));\n        while bytes.has_remaining() {\n            let point = PgPoint {\n                x: bytes.get_f64(),\n                y: bytes.get_f64(),\n            };\n            out_points.push(point)\n        }\n        Ok(PgPolygon { points: out_points })\n    }\n\n    fn serialize(&self, buff: &mut PgArgumentBuffer) -> Result<(), BoxDynError> {\n        let header = self.header();\n        buff.reserve(header.data_size());\n        header.try_write(buff)?;\n\n        for point in &self.points {\n            buff.extend_from_slice(&point.x.to_be_bytes());\n            buff.extend_from_slice(&point.y.to_be_bytes());\n        }\n        Ok(())\n    }\n\n    #[cfg(test)]\n    fn serialize_to_vec(&self) -> Vec<u8> {\n        let mut buff = PgArgumentBuffer::default();\n        self.serialize(&mut buff).unwrap();\n        buff.to_vec()\n    }\n}\n\nimpl Header {\n    const HEADER_WIDTH: usize = mem::size_of::<i8>() + mem::size_of::<i32>();\n\n    fn data_size(&self) -> usize {\n        self.length * BYTE_WIDTH * 2\n    }\n\n    fn try_read(buf: &mut &[u8]) -> Result<Self, String> {\n        if buf.len() < Self::HEADER_WIDTH {\n            return Err(format!(\n                \"expected polygon data to contain at least {} bytes, got {}\",\n                Self::HEADER_WIDTH,\n                buf.len()\n            ));\n        }\n\n        let length = buf.get_i32();\n\n        let length = usize::try_from(length).ok().ok_or_else(|| {\n            format!(\n                \"received polygon with length: {length}. Expected length between 0 and  {}\",\n                usize::MAX\n            )\n        })?;\n\n        Ok(Self { length })\n    }\n\n    fn try_write(&self, buff: &mut PgArgumentBuffer) -> Result<(), String> {\n        let length = i32::try_from(self.length).map_err(|_| {\n            format!(\n                \"polygon length exceeds allowed maximum ({} > {})\",\n                self.length,\n                i32::MAX\n            )\n        })?;\n\n        buff.extend(length.to_be_bytes());\n\n        Ok(())\n    }\n}\n\nfn parse_float_from_str(s: &str, error_msg: &str) -> Result<f64, Error> {\n    s.parse().map_err(|_| Error::Decode(error_msg.into()))\n}\n\n#[cfg(test)]\nmod polygon_tests {\n\n    use std::str::FromStr;\n\n    use crate::types::PgPoint;\n\n    use super::PgPolygon;\n\n    const POLYGON_BYTES: &[u8] = &[\n        0, 0, 0, 12, 192, 0, 0, 0, 0, 0, 0, 0, 192, 8, 0, 0, 0, 0, 0, 0, 191, 240, 0, 0, 0, 0, 0,\n        0, 192, 8, 0, 0, 0, 0, 0, 0, 191, 240, 0, 0, 0, 0, 0, 0, 191, 240, 0, 0, 0, 0, 0, 0, 63,\n        240, 0, 0, 0, 0, 0, 0, 63, 240, 0, 0, 0, 0, 0, 0, 63, 240, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0,\n        0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 8, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 192,\n        8, 0, 0, 0, 0, 0, 0, 63, 240, 0, 0, 0, 0, 0, 0, 192, 8, 0, 0, 0, 0, 0, 0, 63, 240, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191,\n        240, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0, 0, 0, 0, 192, 0, 0, 0, 0,\n        0, 0, 0,\n    ];\n\n    #[test]\n    fn can_deserialise_polygon_type_bytes() {\n        let polygon = PgPolygon::from_bytes(POLYGON_BYTES).unwrap();\n        assert_eq!(\n            polygon,\n            PgPolygon {\n                points: vec![\n                    PgPoint { x: -2., y: -3. },\n                    PgPoint { x: -1., y: -3. },\n                    PgPoint { x: -1., y: -1. },\n                    PgPoint { x: 1., y: 1. },\n                    PgPoint { x: 1., y: 3. },\n                    PgPoint { x: 2., y: 3. },\n                    PgPoint { x: 2., y: -3. },\n                    PgPoint { x: 1., y: -3. },\n                    PgPoint { x: 1., y: 0. },\n                    PgPoint { x: -1., y: 0. },\n                    PgPoint { x: -1., y: -2. },\n                    PgPoint { x: -2., y: -2. }\n                ]\n            }\n        )\n    }\n\n    #[test]\n    fn can_deserialise_polygon_type_str_first_syntax() {\n        let polygon = PgPolygon::from_str(\"[( 1, 2), (3, 4 )]\").unwrap();\n        assert_eq!(\n            polygon,\n            PgPolygon {\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_polygon_type_str_second_syntax() {\n        let polygon = PgPolygon::from_str(\"(( 1, 2), (3, 4 ))\").unwrap();\n        assert_eq!(\n            polygon,\n            PgPolygon {\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn cannot_deserialise_polygon_type_str_uneven_points_first_syntax() {\n        let input_str = \"[( 1, 2), (3)]\";\n        let polygon = PgPolygon::from_str(input_str);\n\n        assert!(polygon.is_err());\n\n        if let Err(err) = polygon {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error occurred while decoding: Unmatched pair in POLYGON: {input_str}\")\n            )\n        }\n    }\n\n    #[test]\n    fn cannot_deserialise_polygon_type_str_invalid_numbers() {\n        let input_str = \"[( 1, 2), (2, three)]\";\n        let polygon = PgPolygon::from_str(input_str);\n\n        assert!(polygon.is_err());\n\n        if let Err(err) = polygon {\n            assert_eq!(\n                err.to_string(),\n                format!(\"error occurred while decoding: could not get y\")\n            )\n        }\n    }\n\n    #[test]\n    fn can_deserialise_polygon_type_str_third_syntax() {\n        let polygon = PgPolygon::from_str(\"(1, 2), (3, 4 )\").unwrap();\n        assert_eq!(\n            polygon,\n            PgPolygon {\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_polygon_type_str_fourth_syntax() {\n        let polygon = PgPolygon::from_str(\"1, 2, 3, 4\").unwrap();\n        assert_eq!(\n            polygon,\n            PgPolygon {\n                points: vec![PgPoint { x: 1., y: 2. }, PgPoint { x: 3., y: 4. }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_deserialise_polygon_type_str_float() {\n        let polygon = PgPolygon::from_str(\"(1.1, 2.2), (3.3, 4.4)\").unwrap();\n        assert_eq!(\n            polygon,\n            PgPolygon {\n                points: vec![PgPoint { x: 1.1, y: 2.2 }, PgPoint { x: 3.3, y: 4.4 }]\n            }\n        );\n    }\n\n    #[test]\n    fn can_serialise_polygon_type() {\n        let polygon = PgPolygon {\n            points: vec![\n                PgPoint { x: -2., y: -3. },\n                PgPoint { x: -1., y: -3. },\n                PgPoint { x: -1., y: -1. },\n                PgPoint { x: 1., y: 1. },\n                PgPoint { x: 1., y: 3. },\n                PgPoint { x: 2., y: 3. },\n                PgPoint { x: 2., y: -3. },\n                PgPoint { x: 1., y: -3. },\n                PgPoint { x: 1., y: 0. },\n                PgPoint { x: -1., y: 0. },\n                PgPoint { x: -1., y: -2. },\n                PgPoint { x: -2., y: -2. },\n            ],\n        };\n        assert_eq!(polygon.serialize_to_vec(), POLYGON_BYTES,)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/hstore.rs",
    "content": "use std::{\n    collections::{btree_map, BTreeMap},\n    mem,\n    ops::{Deref, DerefMut},\n    str,\n};\n\nuse crate::{\n    decode::Decode,\n    encode::{Encode, IsNull},\n    error::BoxDynError,\n    types::Type,\n    PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres,\n};\nuse sqlx_core::bytes::Buf;\n\n/// Key-value support (`hstore`) for Postgres.\n///\n/// SQLx currently maps `hstore` to a `BTreeMap<String, Option<String>>` but this may be expanded in\n/// future to allow for user defined types.\n///\n/// See [the Postgres manual, Appendix F, Section 18][PG.F.18]\n///\n/// [PG.F.18]: https://www.postgresql.org/docs/current/hstore.html\n///\n/// ### Note: Requires Postgres 8.3+\n/// Introduced as a method for storing unstructured data, the `hstore` extension was first added in\n/// Postgres 8.3.\n///\n///\n/// ### Note: Extension Required\n/// The `hstore` extension is not enabled by default in Postgres. You will need to do so explicitly:\n///\n/// ```ignore\n/// CREATE EXTENSION IF NOT EXISTS hstore;\n/// ```\n///\n/// # Examples\n///\n/// ```\n/// # use sqlx_postgres::types::PgHstore;\n/// // Shows basic usage of the PgHstore type.\n/// //\n/// #[derive(Clone, Debug, Default, Eq, PartialEq)]\n/// struct UserCreate<'a> {\n///     username: &'a str,\n///     password: &'a str,\n///     additional_data: PgHstore\n/// }\n///\n/// let mut new_user = UserCreate {\n///     username: \"name.surname@email.com\",\n///     password: \"@super_secret_1\",\n///     ..Default::default()\n/// };\n///\n/// new_user.additional_data.insert(\"department\".to_string(), Some(\"IT\".to_string()));\n/// new_user.additional_data.insert(\"equipment_issued\".to_string(), None);\n/// ```\n/// ```ignore\n/// query_scalar::<_, i64>(\n///     \"insert into user(username, password, additional_data) values($1, $2, $3) returning id\"\n/// )\n/// .bind(new_user.username)\n/// .bind(new_user.password)\n/// .bind(new_user.additional_data)\n/// .fetch_one(pg_conn)\n/// .await?;\n/// ```\n///\n/// ```\n/// # use sqlx_postgres::types::PgHstore;\n/// // PgHstore implements FromIterator to simplify construction.\n/// //\n/// let additional_data = PgHstore::from_iter([\n///     (\"department\".to_string(), Some(\"IT\".to_string())),\n///     (\"equipment_issued\".to_string(), None),\n/// ]);\n///\n/// assert_eq!(additional_data[\"department\"], Some(\"IT\".to_string()));\n/// assert_eq!(additional_data[\"equipment_issued\"], None);\n///\n/// // Also IntoIterator for ease of iteration.\n/// //\n/// for (key, value) in additional_data {\n///     println!(\"{key}: {value:?}\");\n/// }\n/// ```\n///\n#[derive(Clone, Debug, Default, Eq, PartialEq)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct PgHstore(pub BTreeMap<String, Option<String>>);\n\nimpl Deref for PgHstore {\n    type Target = BTreeMap<String, Option<String>>;\n\n    fn deref(&self) -> &Self::Target {\n        &self.0\n    }\n}\n\nimpl DerefMut for PgHstore {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        &mut self.0\n    }\n}\n\nimpl FromIterator<(String, String)> for PgHstore {\n    fn from_iter<T: IntoIterator<Item = (String, String)>>(iter: T) -> Self {\n        iter.into_iter().map(|(k, v)| (k, Some(v))).collect()\n    }\n}\n\nimpl FromIterator<(String, Option<String>)> for PgHstore {\n    fn from_iter<T: IntoIterator<Item = (String, Option<String>)>>(iter: T) -> Self {\n        let mut result = Self::default();\n\n        for (key, value) in iter {\n            result.0.insert(key, value);\n        }\n\n        result\n    }\n}\n\nimpl IntoIterator for PgHstore {\n    type Item = (String, Option<String>);\n    type IntoIter = btree_map::IntoIter<String, Option<String>>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.0.into_iter()\n    }\n}\n\nimpl Type<Postgres> for PgHstore {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"hstore\")\n    }\n}\n\nimpl PgHasArrayType for PgHstore {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::array_of(\"hstore\")\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgHstore {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let mut buf = <&[u8] as Decode<Postgres>>::decode(value)?;\n        let len = read_length(&mut buf)?;\n\n        let len =\n            usize::try_from(len).map_err(|_| format!(\"PgHstore: length out of range: {len}\"))?;\n\n        let mut result = Self::default();\n\n        for i in 0..len {\n            let key = read_string(&mut buf)\n                .map_err(|e| format!(\"PgHstore: error reading {i}th key: {e}\"))?\n                .ok_or_else(|| format!(\"PgHstore: expected {i}th key, got nothing\"))?;\n\n            let value = read_string(&mut buf)\n                .map_err(|e| format!(\"PgHstore: error reading value for key {key:?}: {e}\"))?;\n\n            result.insert(key, value);\n        }\n\n        if !buf.is_empty() {\n            tracing::warn!(\"{} unread bytes at the end of HSTORE value\", buf.len());\n        }\n\n        Ok(result)\n    }\n}\n\nimpl Encode<'_, Postgres> for PgHstore {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend_from_slice(&i32::to_be_bytes(\n            self.0\n                .len()\n                .try_into()\n                .map_err(|_| format!(\"PgHstore length out of range: {}\", self.0.len()))?,\n        ));\n\n        for (i, (key, val)) in self.0.iter().enumerate() {\n            let key_bytes = key.as_bytes();\n\n            let key_len = i32::try_from(key_bytes.len()).map_err(|_| {\n                // Doesn't make sense to print the key itself: it's more than 2 GiB long!\n                format!(\n                    \"PgHstore: length of {i}th key out of range: {} bytes\",\n                    key_bytes.len()\n                )\n            })?;\n\n            buf.extend_from_slice(&i32::to_be_bytes(key_len));\n            buf.extend_from_slice(key_bytes);\n\n            match val {\n                Some(val) => {\n                    let val_bytes = val.as_bytes();\n\n                    let val_len = i32::try_from(val_bytes.len()).map_err(|_| {\n                        format!(\n                            \"PgHstore: value length for key {key:?} out of range: {} bytes\",\n                            val_bytes.len()\n                        )\n                    })?;\n                    buf.extend_from_slice(&i32::to_be_bytes(val_len));\n                    buf.extend_from_slice(val_bytes);\n                }\n                None => {\n                    buf.extend_from_slice(&i32::to_be_bytes(-1));\n                }\n            }\n        }\n\n        Ok(IsNull::No)\n    }\n}\n\nfn read_length(buf: &mut &[u8]) -> Result<i32, String> {\n    if buf.len() < mem::size_of::<i32>() {\n        return Err(format!(\n            \"expected {} bytes, got {}\",\n            mem::size_of::<i32>(),\n            buf.len()\n        ));\n    }\n\n    Ok(buf.get_i32())\n}\n\nfn read_string(buf: &mut &[u8]) -> Result<Option<String>, String> {\n    let len = read_length(buf)?;\n\n    match len {\n        -1 => Ok(None),\n        len => {\n            let len =\n                usize::try_from(len).map_err(|_| format!(\"string length out of range: {len}\"))?;\n\n            if buf.len() < len {\n                return Err(format!(\"expected {len} bytes, got {}\", buf.len()));\n            }\n\n            let (val, rest) = buf.split_at(len);\n            *buf = rest;\n\n            Ok(Some(\n                str::from_utf8(val).map_err(|e| e.to_string())?.to_string(),\n            ))\n        }\n    }\n}\n\n#[cfg(test)]\nmod test {\n    use super::*;\n    use crate::PgValueFormat;\n\n    const EMPTY: &str = \"00000000\";\n\n    const NAME_SURNAME_AGE: &str =\n        \"0000000300000003616765ffffffff000000046e616d65000000044a6f686e000000077375726e616d6500000003446f65\";\n\n    #[test]\n    fn hstore_deserialize_ok() {\n        let empty = hex::decode(EMPTY).unwrap();\n        let name_surname_age = hex::decode(NAME_SURNAME_AGE).unwrap();\n\n        let empty = PgValueRef {\n            value: Some(empty.as_slice()),\n            row: None,\n            type_info: PgTypeInfo::with_name(\"hstore\"),\n            format: PgValueFormat::Binary,\n        };\n\n        let name_surname = PgValueRef {\n            value: Some(name_surname_age.as_slice()),\n            row: None,\n            type_info: PgTypeInfo::with_name(\"hstore\"),\n            format: PgValueFormat::Binary,\n        };\n\n        let res_empty = PgHstore::decode(empty).unwrap();\n        let res_name_surname = PgHstore::decode(name_surname).unwrap();\n\n        assert!(res_empty.is_empty());\n        assert_eq!(res_name_surname[\"name\"], Some(\"John\".to_string()));\n        assert_eq!(res_name_surname[\"surname\"], Some(\"Doe\".to_string()));\n        assert_eq!(res_name_surname[\"age\"], None);\n    }\n\n    #[test]\n    #[should_panic(expected = \"PgHstore: length out of range: -5\")]\n    fn hstore_deserialize_buffer_length_error() {\n        let buf = PgValueRef {\n            value: Some(&[255, 255, 255, 251]),\n            row: None,\n            type_info: PgTypeInfo::with_name(\"hstore\"),\n            format: PgValueFormat::Binary,\n        };\n\n        PgHstore::decode(buf).unwrap();\n    }\n\n    #[test]\n    fn hstore_serialize_ok() {\n        let mut buff = PgArgumentBuffer::default();\n        let _ = PgHstore::from_iter::<[(String, String); 0]>([])\n            .encode_by_ref(&mut buff)\n            .unwrap();\n\n        assert_eq!(hex::encode(buff.as_slice()), EMPTY);\n\n        buff.clear();\n\n        let _ = PgHstore::from_iter([\n            (\"name\".to_string(), Some(\"John\".to_string())),\n            (\"surname\".to_string(), Some(\"Doe\".to_string())),\n            (\"age\".to_string(), None),\n        ])\n        .encode_by_ref(&mut buff)\n        .unwrap();\n\n        assert_eq!(hex::encode(buff.as_slice()), NAME_SURNAME_AGE);\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/int.rs",
    "content": "use byteorder::{BigEndian, ByteOrder};\nuse std::num::{NonZeroI16, NonZeroI32, NonZeroI64};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nfn int_decode(value: PgValueRef<'_>) -> Result<i64, BoxDynError> {\n    Ok(match value.format() {\n        PgValueFormat::Text => value.as_str()?.parse()?,\n        PgValueFormat::Binary => {\n            let buf = value.as_bytes()?;\n\n            // Return error if buf is empty or is more than 8 bytes\n            match buf.len() {\n                0 => {\n                    return Err(\"Value Buffer found empty while decoding to integer type\".into());\n                }\n                buf_len @ 9.. => {\n                    return Err(format!(\n                        \"Value Buffer exceeds 8 bytes while decoding to integer type. Buffer size = {} bytes \", buf_len\n                    )\n                    .into());\n                }\n                _ => {}\n            }\n\n            BigEndian::read_int(buf, buf.len())\n        }\n    })\n}\n\nimpl Type<Postgres> for i8 {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::CHAR\n    }\n}\n\nimpl PgHasArrayType for i8 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::CHAR_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for i8 {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for i8 {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        // note: decoding here is for the `\"char\"` type as Postgres does not have a native 1-byte integer type.\n        // https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/char.c#L58-L60\n        match value.format() {\n            PgValueFormat::Binary => int_decode(value)?.try_into().map_err(Into::into),\n            PgValueFormat::Text => {\n                let text = value.as_str()?;\n\n                // A value of 0 is represented with the empty string.\n                if text.is_empty() {\n                    return Ok(0);\n                }\n\n                if text.starts_with('\\\\') {\n                    // For values between 0x80 and 0xFF, it's encoded in octal.\n                    return Ok(i8::from_str_radix(text.trim_start_matches('\\\\'), 8)?);\n                }\n\n                // Wrapping is the whole idea.\n                #[allow(clippy::cast_possible_wrap)]\n                Ok(text.as_bytes()[0] as i8)\n            }\n        }\n    }\n}\n\nimpl Type<Postgres> for i16 {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INT2\n    }\n}\n\nimpl PgHasArrayType for i16 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT2_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for i16 {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for i16 {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Type<Postgres> for i32 {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INT4\n    }\n}\n\nimpl PgHasArrayType for i32 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT4_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for i32 {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for i32 {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)?.try_into().map_err(Into::into)\n    }\n}\n\nimpl Type<Postgres> for i64 {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INT8\n    }\n}\n\nimpl PgHasArrayType for i64 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT8_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for i64 {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for i64 {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        int_decode(value)\n    }\n}\n\nimpl PgHasArrayType for NonZeroI16 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT2_ARRAY\n    }\n}\n\nimpl PgHasArrayType for NonZeroI32 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT4_ARRAY\n    }\n}\n\nimpl PgHasArrayType for NonZeroI64 {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT8_ARRAY\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/interval.rs",
    "content": "use std::mem;\n\nuse byteorder::{NetworkEndian, ReadBytesExt};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n// `PgInterval` is available for direct access to the INTERVAL type\n\n#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash, Default)]\npub struct PgInterval {\n    pub months: i32,\n    pub days: i32,\n    pub microseconds: i64,\n}\n\nimpl Type<Postgres> for PgInterval {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL\n    }\n}\n\nimpl PgHasArrayType for PgInterval {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL_ARRAY\n    }\n}\n\nimpl<'de> Decode<'de, Postgres> for PgInterval {\n    fn decode(value: PgValueRef<'de>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => {\n                let mut buf = value.as_bytes()?;\n                let microseconds = buf.read_i64::<NetworkEndian>()?;\n                let days = buf.read_i32::<NetworkEndian>()?;\n                let months = buf.read_i32::<NetworkEndian>()?;\n\n                Ok(PgInterval {\n                    months,\n                    days,\n                    microseconds,\n                })\n            }\n\n            // TODO: Implement parsing of text mode\n            PgValueFormat::Text => {\n                Err(\"not implemented: decode `INTERVAL` in text mode (unprepared queries)\".into())\n            }\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for PgInterval {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.microseconds.to_be_bytes());\n        buf.extend(&self.days.to_be_bytes());\n        buf.extend(&self.months.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        2 * mem::size_of::<i64>()\n    }\n}\n\n// We then implement Encode + Type for std Duration, chrono Duration, and time Duration\n// This is to enable ease-of-use for encoding when its simple\n\nimpl Type<Postgres> for std::time::Duration {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL\n    }\n}\n\nimpl PgHasArrayType for std::time::Duration {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for std::time::Duration {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        PgInterval::try_from(*self)?.encode_by_ref(buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        2 * mem::size_of::<i64>()\n    }\n}\n\nimpl TryFrom<std::time::Duration> for PgInterval {\n    type Error = BoxDynError;\n\n    /// Convert a `std::time::Duration` to a `PgInterval`\n    ///\n    /// This returns an error if there is a loss of precision using nanoseconds or if there is a\n    /// microsecond overflow.\n    fn try_from(value: std::time::Duration) -> Result<Self, BoxDynError> {\n        if value.as_nanos() % 1000 != 0 {\n            return Err(\"PostgreSQL `INTERVAL` does not support nanoseconds precision\".into());\n        }\n\n        Ok(Self {\n            months: 0,\n            days: 0,\n            microseconds: value.as_micros().try_into()?,\n        })\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl Type<Postgres> for chrono::Duration {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl PgHasArrayType for chrono::Duration {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL_ARRAY\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl Encode<'_, Postgres> for chrono::Duration {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        let pg_interval = PgInterval::try_from(*self)?;\n        pg_interval.encode_by_ref(buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        2 * mem::size_of::<i64>()\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl TryFrom<chrono::Duration> for PgInterval {\n    type Error = BoxDynError;\n\n    /// Convert a `chrono::Duration` to a `PgInterval`.\n    ///\n    /// This returns an error if there is a loss of precision using nanoseconds or if there is a\n    /// nanosecond overflow.\n    fn try_from(value: chrono::Duration) -> Result<Self, BoxDynError> {\n        value\n            .num_nanoseconds()\n            .map_or::<Result<_, Self::Error>, _>(\n                Err(\"Overflow has occurred for PostgreSQL `INTERVAL`\".into()),\n                |nanoseconds| {\n                    if nanoseconds % 1000 != 0 {\n                        return Err(\n                            \"PostgreSQL `INTERVAL` does not support nanoseconds precision\".into(),\n                        );\n                    }\n                    Ok(())\n                },\n            )?;\n\n        value.num_microseconds().map_or(\n            Err(\"Overflow has occurred for PostgreSQL `INTERVAL`\".into()),\n            |microseconds| {\n                Ok(Self {\n                    months: 0,\n                    days: 0,\n                    microseconds,\n                })\n            },\n        )\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl Type<Postgres> for time::Duration {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl PgHasArrayType for time::Duration {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INTERVAL_ARRAY\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl Encode<'_, Postgres> for time::Duration {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        let pg_interval = PgInterval::try_from(*self)?;\n        pg_interval.encode_by_ref(buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        2 * mem::size_of::<i64>()\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl TryFrom<time::Duration> for PgInterval {\n    type Error = BoxDynError;\n\n    /// Convert a `time::Duration` to a `PgInterval`.\n    ///\n    /// This returns an error if there is a loss of precision using nanoseconds or if there is a\n    /// microsecond overflow.\n    fn try_from(value: time::Duration) -> Result<Self, BoxDynError> {\n        if value.whole_nanoseconds() % 1000 != 0 {\n            return Err(\"PostgreSQL `INTERVAL` does not support nanoseconds precision\".into());\n        }\n\n        Ok(Self {\n            months: 0,\n            days: 0,\n            microseconds: value.whole_microseconds().try_into()?,\n        })\n    }\n}\n\n#[test]\nfn test_encode_interval() {\n    let mut buf = PgArgumentBuffer::default();\n\n    let interval = PgInterval {\n        months: 0,\n        days: 0,\n        microseconds: 0,\n    };\n    assert!(matches!(\n        Encode::<Postgres>::encode(interval, &mut buf),\n        Ok(IsNull::No)\n    ));\n    assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);\n    buf.clear();\n\n    let interval = PgInterval {\n        months: 0,\n        days: 0,\n        microseconds: 1_000,\n    };\n    assert!(matches!(\n        Encode::<Postgres>::encode(interval, &mut buf),\n        Ok(IsNull::No)\n    ));\n    assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 3, 232, 0, 0, 0, 0, 0, 0, 0, 0]);\n    buf.clear();\n\n    let interval = PgInterval {\n        months: 0,\n        days: 0,\n        microseconds: 1_000_000,\n    };\n    assert!(matches!(\n        Encode::<Postgres>::encode(interval, &mut buf),\n        Ok(IsNull::No)\n    ));\n    assert_eq!(&**buf, [0, 0, 0, 0, 0, 15, 66, 64, 0, 0, 0, 0, 0, 0, 0, 0]);\n    buf.clear();\n\n    let interval = PgInterval {\n        months: 0,\n        days: 0,\n        microseconds: 3_600_000_000,\n    };\n    assert!(matches!(\n        Encode::<Postgres>::encode(interval, &mut buf),\n        Ok(IsNull::No)\n    ));\n    assert_eq!(\n        &**buf,\n        [0, 0, 0, 0, 214, 147, 164, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n    );\n    buf.clear();\n\n    let interval = PgInterval {\n        months: 0,\n        days: 1,\n        microseconds: 0,\n    };\n    assert!(matches!(\n        Encode::<Postgres>::encode(interval, &mut buf),\n        Ok(IsNull::No)\n    ));\n    assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0]);\n    buf.clear();\n\n    let interval = PgInterval {\n        months: 1,\n        days: 0,\n        microseconds: 0,\n    };\n    assert!(matches!(\n        Encode::<Postgres>::encode(interval, &mut buf),\n        Ok(IsNull::No)\n    ));\n    assert_eq!(&**buf, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);\n    buf.clear();\n\n    assert_eq!(\n        PgInterval::default(),\n        PgInterval {\n            months: 0,\n            days: 0,\n            microseconds: 0,\n        }\n    );\n}\n\n#[test]\nfn test_pginterval_std() {\n    // Case for positive duration\n    let interval = PgInterval {\n        days: 0,\n        months: 0,\n        microseconds: 27_000,\n    };\n    assert_eq!(\n        &PgInterval::try_from(std::time::Duration::from_micros(27_000)).unwrap(),\n        &interval\n    );\n\n    // Case when precision loss occurs\n    assert!(PgInterval::try_from(std::time::Duration::from_nanos(27_000_001)).is_err());\n\n    // Case when microsecond overflow occurs\n    assert!(PgInterval::try_from(std::time::Duration::from_secs(20_000_000_000_000)).is_err());\n}\n\n#[test]\n#[cfg(feature = \"chrono\")]\nfn test_pginterval_chrono() {\n    // Case for positive duration\n    let interval = PgInterval {\n        days: 0,\n        months: 0,\n        microseconds: 27_000,\n    };\n    assert_eq!(\n        &PgInterval::try_from(chrono::Duration::microseconds(27_000)).unwrap(),\n        &interval\n    );\n\n    // Case for negative duration\n    let interval = PgInterval {\n        days: 0,\n        months: 0,\n        microseconds: -27_000,\n    };\n    assert_eq!(\n        &PgInterval::try_from(chrono::Duration::microseconds(-27_000)).unwrap(),\n        &interval\n    );\n\n    // Case when precision loss occurs\n    assert!(PgInterval::try_from(chrono::Duration::nanoseconds(27_000_001)).is_err());\n    assert!(PgInterval::try_from(chrono::Duration::nanoseconds(-27_000_001)).is_err());\n\n    // Case when nanosecond overflow occurs\n    assert!(PgInterval::try_from(chrono::Duration::seconds(10_000_000_000)).is_err());\n    assert!(PgInterval::try_from(chrono::Duration::seconds(-10_000_000_000)).is_err());\n}\n\n#[test]\n#[cfg(feature = \"time\")]\nfn test_pginterval_time() {\n    // Case for positive duration\n    let interval = PgInterval {\n        days: 0,\n        months: 0,\n        microseconds: 27_000,\n    };\n    assert_eq!(\n        &PgInterval::try_from(time::Duration::microseconds(27_000)).unwrap(),\n        &interval\n    );\n\n    // Case for negative duration\n    let interval = PgInterval {\n        days: 0,\n        months: 0,\n        microseconds: -27_000,\n    };\n    assert_eq!(\n        &PgInterval::try_from(time::Duration::microseconds(-27_000)).unwrap(),\n        &interval\n    );\n\n    // Case when precision loss occurs\n    assert!(PgInterval::try_from(time::Duration::nanoseconds(27_000_001)).is_err());\n    assert!(PgInterval::try_from(time::Duration::nanoseconds(-27_000_001)).is_err());\n\n    // Case when microsecond overflow occurs\n    assert!(PgInterval::try_from(time::Duration::seconds(10_000_000_000_000)).is_err());\n    assert!(PgInterval::try_from(time::Duration::seconds(-10_000_000_000_000)).is_err());\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/ipnet/ipaddr.rs",
    "content": "use std::net::IpAddr;\n\nuse ipnet::IpNet;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};\n\nimpl Type<Postgres> for IpAddr\nwhere\n    IpNet: Type<Postgres>,\n{\n    fn type_info() -> PgTypeInfo {\n        IpNet::type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        IpNet::compatible(ty)\n    }\n}\n\nimpl PgHasArrayType for IpAddr {\n    fn array_type_info() -> PgTypeInfo {\n        <IpNet as PgHasArrayType>::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        <IpNet as PgHasArrayType>::array_compatible(ty)\n    }\n}\n\nimpl<'db> Encode<'db, Postgres> for IpAddr\nwhere\n    IpNet: Encode<'db, Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        IpNet::from(*self).encode_by_ref(buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        IpNet::from(*self).size_hint()\n    }\n}\n\nimpl<'db> Decode<'db, Postgres> for IpAddr\nwhere\n    IpNet: Decode<'db, Postgres>,\n{\n    fn decode(value: PgValueRef<'db>) -> Result<Self, BoxDynError> {\n        let ipnet = IpNet::decode(value)?;\n\n        if matches!(ipnet, IpNet::V4(net) if net.prefix_len() != 32)\n            || matches!(ipnet, IpNet::V6(net) if net.prefix_len() != 128)\n        {\n            Err(\"lossy decode from inet/cidr\")?\n        }\n\n        Ok(ipnet.addr())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/ipnet/ipnet.rs",
    "content": "use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};\n\n#[cfg(feature = \"ipnet\")]\nuse ipnet::{IpNet, Ipv4Net, Ipv6Net};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/include/utils/inet.h#L39\n\n// Technically this is a magic number here but it doesn't make sense to drag in the whole of `libc`\n// just for one constant.\nconst PGSQL_AF_INET: u8 = 2; // AF_INET\nconst PGSQL_AF_INET6: u8 = PGSQL_AF_INET + 1;\n\nimpl Type<Postgres> for IpNet {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INET\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::CIDR || *ty == PgTypeInfo::INET\n    }\n}\n\nimpl PgHasArrayType for IpNet {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INET_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::CIDR_ARRAY || *ty == PgTypeInfo::INET_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for IpNet {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L293\n        // https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L271\n\n        match self {\n            IpNet::V4(net) => {\n                buf.push(PGSQL_AF_INET); // ip_family\n                buf.push(net.prefix_len()); // ip_bits\n                buf.push(0); // is_cidr\n                buf.push(4); // nb (number of bytes)\n                buf.extend_from_slice(&net.addr().octets()) // address\n            }\n\n            IpNet::V6(net) => {\n                buf.push(PGSQL_AF_INET6); // ip_family\n                buf.push(net.prefix_len()); // ip_bits\n                buf.push(0); // is_cidr\n                buf.push(16); // nb (number of bytes)\n                buf.extend_from_slice(&net.addr().octets()); // address\n            }\n        }\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        match self {\n            IpNet::V4(_) => 8,\n            IpNet::V6(_) => 20,\n        }\n    }\n}\n\nimpl Decode<'_, Postgres> for IpNet {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        let bytes = match value.format() {\n            PgValueFormat::Binary => value.as_bytes()?,\n            PgValueFormat::Text => {\n                let s = value.as_str()?;\n                println!(\"{s}\");\n                if s.contains('/') {\n                    return Ok(s.parse()?);\n                }\n                // IpNet::from_str doesn't handle conversion from IpAddr to IpNet\n                let addr: IpAddr = s.parse()?;\n                return Ok(addr.into());\n            }\n        };\n\n        if bytes.len() >= 8 {\n            let family = bytes[0];\n            let prefix = bytes[1];\n            let _is_cidr = bytes[2] != 0;\n            let len = bytes[3];\n\n            match family {\n                PGSQL_AF_INET => {\n                    if bytes.len() == 8 && len == 4 {\n                        let inet = Ipv4Net::new(\n                            Ipv4Addr::new(bytes[4], bytes[5], bytes[6], bytes[7]),\n                            prefix,\n                        )?;\n\n                        return Ok(IpNet::V4(inet));\n                    }\n                }\n\n                PGSQL_AF_INET6 => {\n                    if bytes.len() == 20 && len == 16 {\n                        let inet = Ipv6Net::new(\n                            Ipv6Addr::from([\n                                bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9],\n                                bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],\n                                bytes[16], bytes[17], bytes[18], bytes[19],\n                            ]),\n                            prefix,\n                        )?;\n\n                        return Ok(IpNet::V6(inet));\n                    }\n                }\n\n                _ => {\n                    return Err(format!(\"unknown ip family {family}\").into());\n                }\n            }\n        }\n\n        Err(\"invalid data received when expecting an INET\".into())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/ipnet/mod.rs",
    "content": "// Prefer `ipnetwork` over `ipnet` because it was implemented first (want to avoid breaking change).\n#[cfg(not(feature = \"ipnetwork\"))]\nmod ipaddr;\n\n// Parent module is named after the `ipnet` crate, this is named after the `IpNet` type.\n#[allow(clippy::module_inception)]\nmod ipnet;\n"
  },
  {
    "path": "sqlx-postgres/src/types/ipnetwork/ipaddr.rs",
    "content": "use std::net::IpAddr;\n\nuse ipnetwork::IpNetwork;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};\n\nimpl Type<Postgres> for IpAddr\nwhere\n    IpNetwork: Type<Postgres>,\n{\n    fn type_info() -> PgTypeInfo {\n        IpNetwork::type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        IpNetwork::compatible(ty)\n    }\n}\n\nimpl PgHasArrayType for IpAddr {\n    fn array_type_info() -> PgTypeInfo {\n        <IpNetwork as PgHasArrayType>::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        <IpNetwork as PgHasArrayType>::array_compatible(ty)\n    }\n}\n\nimpl<'db> Encode<'db, Postgres> for IpAddr\nwhere\n    IpNetwork: Encode<'db, Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        IpNetwork::from(*self).encode_by_ref(buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        IpNetwork::from(*self).size_hint()\n    }\n}\n\nimpl<'db> Decode<'db, Postgres> for IpAddr\nwhere\n    IpNetwork: Decode<'db, Postgres>,\n{\n    fn decode(value: PgValueRef<'db>) -> Result<Self, BoxDynError> {\n        let ipnetwork = IpNetwork::decode(value)?;\n\n        if ipnetwork.is_ipv4() && ipnetwork.prefix() != 32\n            || ipnetwork.is_ipv6() && ipnetwork.prefix() != 128\n        {\n            Err(\"lossy decode from inet/cidr\")?\n        }\n\n        Ok(ipnetwork.ip())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/ipnetwork/ipnetwork.rs",
    "content": "use std::net::{Ipv4Addr, Ipv6Addr};\n\nuse ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n// https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/include/utils/inet.h#L39\n\n// Technically this is a magic number here but it doesn't make sense to drag in the whole of `libc`\n// just for one constant.\nconst PGSQL_AF_INET: u8 = 2; // AF_INET\nconst PGSQL_AF_INET6: u8 = PGSQL_AF_INET + 1;\n\nimpl Type<Postgres> for IpNetwork {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INET\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::CIDR || *ty == PgTypeInfo::INET\n    }\n}\n\nimpl PgHasArrayType for IpNetwork {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INET_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::CIDR_ARRAY || *ty == PgTypeInfo::INET_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for IpNetwork {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L293\n        // https://github.com/postgres/postgres/blob/574925bfd0a8175f6e161936ea11d9695677ba09/src/backend/utils/adt/network.c#L271\n\n        match self {\n            IpNetwork::V4(net) => {\n                buf.push(PGSQL_AF_INET); // ip_family\n                buf.push(net.prefix()); // ip_bits\n                buf.push(0); // is_cidr\n                buf.push(4); // nb (number of bytes)\n                buf.extend_from_slice(&net.ip().octets()) // address\n            }\n\n            IpNetwork::V6(net) => {\n                buf.push(PGSQL_AF_INET6); // ip_family\n                buf.push(net.prefix()); // ip_bits\n                buf.push(0); // is_cidr\n                buf.push(16); // nb (number of bytes)\n                buf.extend_from_slice(&net.ip().octets()); // address\n            }\n        }\n\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        match self {\n            IpNetwork::V4(_) => 8,\n            IpNetwork::V6(_) => 20,\n        }\n    }\n}\n\nimpl Decode<'_, Postgres> for IpNetwork {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        let bytes = match value.format() {\n            PgValueFormat::Binary => value.as_bytes()?,\n            PgValueFormat::Text => {\n                return Ok(value.as_str()?.parse()?);\n            }\n        };\n\n        if bytes.len() >= 8 {\n            let family = bytes[0];\n            let prefix = bytes[1];\n            let _is_cidr = bytes[2] != 0;\n            let len = bytes[3];\n\n            match family {\n                PGSQL_AF_INET => {\n                    if bytes.len() == 8 && len == 4 {\n                        let inet = Ipv4Network::new(\n                            Ipv4Addr::new(bytes[4], bytes[5], bytes[6], bytes[7]),\n                            prefix,\n                        )?;\n\n                        return Ok(IpNetwork::V4(inet));\n                    }\n                }\n\n                PGSQL_AF_INET6 => {\n                    if bytes.len() == 20 && len == 16 {\n                        let inet = Ipv6Network::new(\n                            Ipv6Addr::from([\n                                bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9],\n                                bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],\n                                bytes[16], bytes[17], bytes[18], bytes[19],\n                            ]),\n                            prefix,\n                        )?;\n\n                        return Ok(IpNetwork::V6(inet));\n                    }\n                }\n\n                _ => {\n                    return Err(format!(\"unknown ip family {family}\").into());\n                }\n            }\n        }\n\n        Err(\"invalid data received when expecting an INET\".into())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/ipnetwork/mod.rs",
    "content": "mod ipaddr;\n\n// Parent module is named after the `ipnetwork` crate, this is named after the `IpNetwork` type.\n#[allow(clippy::module_inception)]\nmod ipnetwork;\n"
  },
  {
    "path": "sqlx-postgres/src/types/json.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::array_compatible;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse serde::{Deserialize, Serialize};\nuse serde_json::value::RawValue as JsonRawValue;\nuse serde_json::Value as JsonValue;\npub(crate) use sqlx_core::types::{Json, Type};\n\n// <https://www.postgresql.org/docs/12/datatype-json.html>\n\n// In general, most applications should prefer to store JSON data as jsonb,\n// unless there are quite specialized needs, such as legacy assumptions\n// about ordering of object keys.\n\nimpl<T> Type<Postgres> for Json<T> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::JSONB\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::JSON || *ty == PgTypeInfo::JSONB\n    }\n}\n\nimpl<T> PgHasArrayType for Json<T> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::JSONB_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        array_compatible::<Json<T>>(ty)\n    }\n}\n\nimpl PgHasArrayType for JsonValue {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::JSONB_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        array_compatible::<JsonValue>(ty)\n    }\n}\n\nimpl PgHasArrayType for JsonRawValue {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::JSONB_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        array_compatible::<JsonRawValue>(ty)\n    }\n}\n\nimpl<T> Encode<'_, Postgres> for Json<T>\nwhere\n    T: Serialize,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // we have a tiny amount of dynamic behavior depending if we are resolved to be JSON\n        // instead of JSONB\n        buf.patch(|buf, ty: &PgTypeInfo| {\n            if *ty == PgTypeInfo::JSON || *ty == PgTypeInfo::JSON_ARRAY {\n                buf[0] = b' ';\n            }\n        });\n\n        // JSONB version (as of 2020-03-20)\n        buf.push(1);\n\n        // the JSON data written to the buffer is the same regardless of parameter type\n        serde_json::to_writer(&mut **buf, &self.0)?;\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r, T: 'r> Decode<'r, Postgres> for Json<T>\nwhere\n    T: Deserialize<'r>,\n{\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let mut buf = value.as_bytes()?;\n\n        if value.format() == PgValueFormat::Binary && value.type_info == PgTypeInfo::JSONB {\n            assert_eq!(\n                buf[0], 1,\n                \"unsupported JSONB format version {}; please open an issue\",\n                buf[0]\n            );\n\n            buf = &buf[1..];\n        }\n\n        serde_json::from_slice(buf).map(Json).map_err(Into::into)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/lquery.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse bitflags::bitflags;\nuse std::fmt::{self, Display, Formatter};\nuse std::io::Write;\nuse std::ops::Deref;\nuse std::str::FromStr;\n\nuse crate::types::ltree::{PgLTreeLabel, PgLTreeParseError};\n\n/// Represents lquery specific errors\n#[derive(Debug, thiserror::Error)]\n#[non_exhaustive]\npub enum PgLQueryParseError {\n    #[error(\"lquery cannot be empty\")]\n    EmptyString,\n    #[error(\"unexpected character in lquery\")]\n    UnexpectedCharacter,\n    #[error(\"error parsing integer: {0}\")]\n    ParseIntError(#[from] std::num::ParseIntError),\n    #[error(\"error parsing integer: {0}\")]\n    LTreeParrseError(#[from] PgLTreeParseError),\n    /// LQuery version not supported\n    #[error(\"lquery version not supported\")]\n    InvalidLqueryVersion,\n}\n\n/// Container for a Label Tree Query (`lquery`) in Postgres.\n///\n/// See <https://www.postgresql.org/docs/current/ltree.html>\n///\n/// ### Note: Requires Postgres 13+\n///\n/// This integration requires that the `lquery` type support the binary format in the Postgres\n/// wire protocol, which only became available in Postgres 13.\n/// ([Postgres 13.0 Release Notes, Additional Modules](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.11.5.14))\n///\n/// Ideally, SQLx's Postgres driver should support falling back to text format for types\n/// which don't have `typsend` and `typrecv` entries in `pg_type`, but that work still needs\n/// to be done.\n///\n/// ### Note: Extension Required\n/// The `ltree` extension is not enabled by default in Postgres. You will need to do so explicitly:\n///\n/// ```ignore\n/// CREATE EXTENSION IF NOT EXISTS \"ltree\";\n/// ```\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct PgLQuery {\n    levels: Vec<PgLQueryLevel>,\n}\n\n// TODO: maybe a QueryBuilder pattern would be nice here\nimpl PgLQuery {\n    /// creates default/empty lquery\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    pub fn from(levels: Vec<PgLQueryLevel>) -> Self {\n        Self { levels }\n    }\n\n    /// push a query level\n    pub fn push(&mut self, level: PgLQueryLevel) {\n        self.levels.push(level);\n    }\n\n    /// pop a query level\n    pub fn pop(&mut self) -> Option<PgLQueryLevel> {\n        self.levels.pop()\n    }\n\n    /// creates lquery from an iterator with checking labels\n    // TODO: this should just be removed but I didn't want to bury it in a massive diff\n    #[deprecated = \"renamed to `try_from_iter()`\"]\n    #[allow(clippy::should_implement_trait)]\n    pub fn from_iter<I, S>(levels: I) -> Result<Self, PgLQueryParseError>\n    where\n        S: Into<String>,\n        I: IntoIterator<Item = S>,\n    {\n        let mut lquery = Self::default();\n        for level in levels {\n            lquery.push(PgLQueryLevel::from_str(&level.into())?);\n        }\n        Ok(lquery)\n    }\n\n    /// Create an `LQUERY` from an iterator of label strings.\n    ///\n    /// Returns an error if any label fails to parse according to [`PgLQueryLevel::from_str()`].\n    pub fn try_from_iter<I, S>(levels: I) -> Result<Self, PgLQueryParseError>\n    where\n        S: AsRef<str>,\n        I: IntoIterator<Item = S>,\n    {\n        levels\n            .into_iter()\n            .map(|level| level.as_ref().parse::<PgLQueryLevel>())\n            .collect()\n    }\n}\n\nimpl FromIterator<PgLQueryLevel> for PgLQuery {\n    fn from_iter<T: IntoIterator<Item = PgLQueryLevel>>(iter: T) -> Self {\n        Self::from(iter.into_iter().collect())\n    }\n}\n\nimpl IntoIterator for PgLQuery {\n    type Item = PgLQueryLevel;\n    type IntoIter = std::vec::IntoIter<Self::Item>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.levels.into_iter()\n    }\n}\n\nimpl FromStr for PgLQuery {\n    type Err = PgLQueryParseError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(Self {\n            levels: s\n                .split('.')\n                .map(PgLQueryLevel::from_str)\n                .collect::<Result<_, Self::Err>>()?,\n        })\n    }\n}\n\nimpl Display for PgLQuery {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        let mut iter = self.levels.iter();\n        if let Some(label) = iter.next() {\n            write!(f, \"{label}\")?;\n            for label in iter {\n                write!(f, \".{label}\")?;\n            }\n        }\n        Ok(())\n    }\n}\n\nimpl Deref for PgLQuery {\n    type Target = [PgLQueryLevel];\n\n    fn deref(&self) -> &Self::Target {\n        &self.levels\n    }\n}\n\nimpl Type<Postgres> for PgLQuery {\n    fn type_info() -> PgTypeInfo {\n        // Since `ltree` is enabled by an extension, it does not have a stable OID.\n        PgTypeInfo::with_name(\"lquery\")\n    }\n}\n\nimpl PgHasArrayType for PgLQuery {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_lquery\")\n    }\n}\n\nimpl Encode<'_, Postgres> for PgLQuery {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(1i8.to_le_bytes());\n        write!(buf, \"{self}\")?;\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgLQuery {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => {\n                let bytes = value.as_bytes()?;\n                let version = i8::from_le_bytes([bytes[0]; 1]);\n                if version != 1 {\n                    return Err(Box::new(PgLQueryParseError::InvalidLqueryVersion));\n                }\n                Ok(Self::from_str(std::str::from_utf8(&bytes[1..])?)?)\n            }\n            PgValueFormat::Text => Ok(Self::from_str(value.as_str()?)?),\n        }\n    }\n}\n\nbitflags! {\n    /// Modifiers that can be set to non-star labels\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\n    pub struct PgLQueryVariantFlag: u16 {\n        /// * - Match any label with this prefix, for example foo* matches foobar\n        const ANY_END = 0x01;\n        /// @ - Match case-insensitively, for example a@ matches A\n        const IN_CASE = 0x02;\n        /// % - Match initial underscore-separated words\n        const SUBLEXEME = 0x04;\n    }\n}\n\nimpl Display for PgLQueryVariantFlag {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        if self.contains(PgLQueryVariantFlag::ANY_END) {\n            write!(f, \"*\")?;\n        }\n        if self.contains(PgLQueryVariantFlag::IN_CASE) {\n            write!(f, \"@\")?;\n        }\n        if self.contains(PgLQueryVariantFlag::SUBLEXEME) {\n            write!(f, \"%\")?;\n        }\n\n        Ok(())\n    }\n}\n\n#[derive(Clone, Debug, PartialEq)]\npub struct PgLQueryVariant {\n    label: PgLTreeLabel,\n    modifiers: PgLQueryVariantFlag,\n}\n\nimpl Display for PgLQueryVariant {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}{}\", self.label, self.modifiers)\n    }\n}\n\n#[derive(Clone, Debug, PartialEq)]\npub enum PgLQueryLevel {\n    /// match any label (*) with optional at least / at most numbers\n    Star(Option<u16>, Option<u16>),\n    /// match any of specified labels with optional flags\n    NonStar(Vec<PgLQueryVariant>),\n    /// match none of specified labels with optional flags\n    NotNonStar(Vec<PgLQueryVariant>),\n}\n\nimpl FromStr for PgLQueryLevel {\n    type Err = PgLQueryParseError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let bytes = s.as_bytes();\n        if bytes.is_empty() {\n            Err(PgLQueryParseError::EmptyString)\n        } else {\n            match bytes[0] {\n                b'*' => {\n                    if bytes.len() > 1 {\n                        let parts = s[2..s.len() - 1].split(',').collect::<Vec<_>>();\n                        match parts.len() {\n                            1 => {\n                                let number = parts[0].parse()?;\n                                Ok(PgLQueryLevel::Star(Some(number), Some(number)))\n                            }\n                            2 => Ok(PgLQueryLevel::Star(\n                                Some(parts[0].parse()?),\n                                Some(parts[1].parse()?),\n                            )),\n                            _ => Err(PgLQueryParseError::UnexpectedCharacter),\n                        }\n                    } else {\n                        Ok(PgLQueryLevel::Star(None, None))\n                    }\n                }\n                b'!' => Ok(PgLQueryLevel::NotNonStar(\n                    s[1..]\n                        .split('|')\n                        .map(PgLQueryVariant::from_str)\n                        .collect::<Result<Vec<_>, PgLQueryParseError>>()?,\n                )),\n                _ => Ok(PgLQueryLevel::NonStar(\n                    s.split('|')\n                        .map(PgLQueryVariant::from_str)\n                        .collect::<Result<Vec<_>, PgLQueryParseError>>()?,\n                )),\n            }\n        }\n    }\n}\n\nimpl FromStr for PgLQueryVariant {\n    type Err = PgLQueryParseError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let mut label_length = s.len();\n        let mut modifiers = PgLQueryVariantFlag::empty();\n\n        for b in s.bytes().rev() {\n            match b {\n                b'@' => modifiers.insert(PgLQueryVariantFlag::IN_CASE),\n                b'*' => modifiers.insert(PgLQueryVariantFlag::ANY_END),\n                b'%' => modifiers.insert(PgLQueryVariantFlag::SUBLEXEME),\n                _ => break,\n            }\n            label_length -= 1;\n        }\n\n        Ok(PgLQueryVariant {\n            label: PgLTreeLabel::new(&s[0..label_length])?,\n            modifiers,\n        })\n    }\n}\n\nfn write_variants(f: &mut Formatter<'_>, variants: &[PgLQueryVariant], not: bool) -> fmt::Result {\n    let mut iter = variants.iter();\n    if let Some(variant) = iter.next() {\n        write!(f, \"{}{}\", if not { \"!\" } else { \"\" }, variant)?;\n        for variant in iter {\n            write!(f, \".{variant}\")?;\n        }\n    }\n    Ok(())\n}\n\nimpl Display for PgLQueryLevel {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        match self {\n            PgLQueryLevel::Star(Some(at_least), Some(at_most)) => {\n                if at_least == at_most {\n                    write!(f, \"*{{{at_least}}}\")\n                } else {\n                    write!(f, \"*{{{at_least},{at_most}}}\")\n                }\n            }\n            PgLQueryLevel::Star(Some(at_least), _) => write!(f, \"*{{{at_least},}}\"),\n            PgLQueryLevel::Star(_, Some(at_most)) => write!(f, \"*{{,{at_most}}}\"),\n            PgLQueryLevel::Star(_, _) => write!(f, \"*\"),\n            PgLQueryLevel::NonStar(variants) => write_variants(f, variants, false),\n            PgLQueryLevel::NotNonStar(variants) => write_variants(f, variants, true),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/ltree.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse std::fmt::{self, Display, Formatter};\nuse std::io::Write;\nuse std::ops::Deref;\nuse std::str::FromStr;\n\n/// Represents ltree specific errors\n#[derive(Debug, thiserror::Error)]\n#[non_exhaustive]\npub enum PgLTreeParseError {\n    /// LTree labels can only contain [A-Za-z0-9_]\n    #[error(\"ltree label contains invalid characters\")]\n    InvalidLtreeLabel,\n\n    /// LTree version not supported\n    #[error(\"ltree version not supported\")]\n    InvalidLtreeVersion,\n}\n\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct PgLTreeLabel(String);\n\nimpl PgLTreeLabel {\n    pub fn new<S>(label: S) -> Result<Self, PgLTreeParseError>\n    where\n        S: Into<String>,\n    {\n        let label = label.into();\n        if label.len() <= 256\n            && label\n                .bytes()\n                .all(|c| c.is_ascii_alphabetic() || c.is_ascii_digit() || c == b'_')\n        {\n            Ok(Self(label))\n        } else {\n            Err(PgLTreeParseError::InvalidLtreeLabel)\n        }\n    }\n}\n\nimpl Deref for PgLTreeLabel {\n    type Target = str;\n\n    fn deref(&self) -> &Self::Target {\n        self.0.as_str()\n    }\n}\n\nimpl FromStr for PgLTreeLabel {\n    type Err = PgLTreeParseError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        PgLTreeLabel::new(s)\n    }\n}\n\nimpl Display for PgLTreeLabel {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.0)\n    }\n}\n\n/// Container for a Label Tree (`ltree`) in Postgres.\n///\n/// See <https://www.postgresql.org/docs/current/ltree.html>\n///\n/// ### Note: Requires Postgres 13+\n///\n/// This integration requires that the `ltree` type support the binary format in the Postgres\n/// wire protocol, which only became available in Postgres 13.\n/// ([Postgres 13.0 Release Notes, Additional Modules](https://www.postgresql.org/docs/13/release-13.html#id-1.11.6.11.5.14))\n///\n/// Ideally, SQLx's Postgres driver should support falling back to text format for types\n/// which don't have `typsend` and `typrecv` entries in `pg_type`, but that work still needs\n/// to be done.\n///\n/// ### Note: Extension Required\n/// The `ltree` extension is not enabled by default in Postgres. You will need to do so explicitly:\n///\n/// ```ignore\n/// CREATE EXTENSION IF NOT EXISTS \"ltree\";\n/// ```\n#[derive(Clone, Debug, Default, PartialEq)]\npub struct PgLTree {\n    labels: Vec<PgLTreeLabel>,\n}\n\nimpl PgLTree {\n    /// creates default/empty ltree\n    pub fn new() -> Self {\n        Self::default()\n    }\n\n    /// creates ltree from a [`Vec<PgLTreeLabel>`]\n    pub fn from_labels(labels: Vec<PgLTreeLabel>) -> Self {\n        Self { labels }\n    }\n\n    /// creates ltree from an iterator with checking labels\n    // TODO: this should just be removed but I didn't want to bury it in a massive diff\n    #[deprecated = \"renamed to `try_from_iter()`\"]\n    #[allow(clippy::should_implement_trait)]\n    pub fn from_iter<I, S>(labels: I) -> Result<Self, PgLTreeParseError>\n    where\n        String: From<S>,\n        I: IntoIterator<Item = S>,\n    {\n        let mut ltree = Self::default();\n        for label in labels {\n            ltree.push(PgLTreeLabel::new(label)?);\n        }\n        Ok(ltree)\n    }\n\n    /// Create an `LTREE` from an iterator of label strings.\n    ///\n    /// Returns an error if any label fails to parse according to [`PgLTreeLabel::new()`].\n    pub fn try_from_iter<I, S>(labels: I) -> Result<Self, PgLTreeParseError>\n    where\n        S: Into<String>,\n        I: IntoIterator<Item = S>,\n    {\n        labels.into_iter().map(PgLTreeLabel::new).collect()\n    }\n\n    /// push a label to ltree\n    pub fn push(&mut self, label: PgLTreeLabel) {\n        self.labels.push(label);\n    }\n\n    /// pop a label from ltree\n    pub fn pop(&mut self) -> Option<PgLTreeLabel> {\n        self.labels.pop()\n    }\n}\n\nimpl From<Vec<PgLTreeLabel>> for PgLTree {\n    fn from(labels: Vec<PgLTreeLabel>) -> Self {\n        Self { labels }\n    }\n}\n\nimpl FromIterator<PgLTreeLabel> for PgLTree {\n    fn from_iter<T: IntoIterator<Item = PgLTreeLabel>>(iter: T) -> Self {\n        Self {\n            labels: iter.into_iter().collect(),\n        }\n    }\n}\n\nimpl IntoIterator for PgLTree {\n    type Item = PgLTreeLabel;\n    type IntoIter = std::vec::IntoIter<Self::Item>;\n\n    fn into_iter(self) -> Self::IntoIter {\n        self.labels.into_iter()\n    }\n}\n\nimpl FromStr for PgLTree {\n    type Err = PgLTreeParseError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        Ok(Self {\n            labels: s\n                .split('.')\n                .map(PgLTreeLabel::new)\n                .collect::<Result<Vec<_>, Self::Err>>()?,\n        })\n    }\n}\n\nimpl Display for PgLTree {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        let mut iter = self.labels.iter();\n        if let Some(label) = iter.next() {\n            write!(f, \"{label}\")?;\n            for label in iter {\n                write!(f, \".{label}\")?;\n            }\n        }\n        Ok(())\n    }\n}\n\nimpl Deref for PgLTree {\n    type Target = [PgLTreeLabel];\n\n    fn deref(&self) -> &Self::Target {\n        &self.labels\n    }\n}\n\nimpl Type<Postgres> for PgLTree {\n    fn type_info() -> PgTypeInfo {\n        // Since `ltree` is enabled by an extension, it does not have a stable OID.\n        PgTypeInfo::with_name(\"ltree\")\n    }\n}\n\nimpl PgHasArrayType for PgLTree {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::with_name(\"_ltree\")\n    }\n}\n\nimpl Encode<'_, Postgres> for PgLTree {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(1i8.to_le_bytes());\n        write!(buf, \"{self}\")?;\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PgLTree {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => {\n                let bytes = value.as_bytes()?;\n                let version = i8::from_le_bytes([bytes[0]; 1]);\n                if version != 1 {\n                    return Err(Box::new(PgLTreeParseError::InvalidLtreeVersion));\n                }\n                Ok(Self::from_str(std::str::from_utf8(&bytes[1..])?)?)\n            }\n            PgValueFormat::Text => Ok(Self::from_str(value.as_str()?)?),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/mac_address.rs",
    "content": "use mac_address::MacAddress;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl Type<Postgres> for MacAddress {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::MACADDR\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        *ty == PgTypeInfo::MACADDR\n    }\n}\n\nimpl PgHasArrayType for MacAddress {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::MACADDR_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for MacAddress {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend_from_slice(&self.bytes()); // write just the address\n        Ok(IsNull::No)\n    }\n\n    fn size_hint(&self) -> usize {\n        6\n    }\n}\n\nimpl Decode<'_, Postgres> for MacAddress {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        let bytes = match value.format() {\n            PgValueFormat::Binary => value.as_bytes()?,\n            PgValueFormat::Text => {\n                return Ok(value.as_str()?.parse()?);\n            }\n        };\n\n        if bytes.len() == 6 {\n            return Ok(MacAddress::new(bytes.try_into().unwrap()));\n        }\n\n        Err(\"invalid data received when expecting an MACADDR\".into())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/mod.rs",
    "content": "//! Conversions between Rust and **Postgres** types.\n//!\n//! # Types\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bool`                                | BOOL                                                 |\n//! | `i8`                                  | \"CHAR\"                                               |\n//! | `i16`                                 | SMALLINT, SMALLSERIAL, INT2                          |\n//! | `i32`                                 | INT, SERIAL, INT4                                    |\n//! | `i64`                                 | BIGINT, BIGSERIAL, INT8                              |\n//! | `f32`                                 | REAL, FLOAT4                                         |\n//! | `f64`                                 | DOUBLE PRECISION, FLOAT8                             |\n//! | `&str`, [`String`]                    | VARCHAR, CHAR(N), TEXT, NAME, CITEXT                 |\n//! | `&[u8]`, `Vec<u8>`                    | BYTEA                                                |\n//! | `()`                                  | VOID                                                 |\n//! | [`PgInterval`]                        | INTERVAL                                             |\n//! | [`PgRange<T>`](PgRange)               | INT8RANGE, INT4RANGE, TSRANGE, TSTZRANGE, DATERANGE, NUMRANGE |\n//! | [`PgMoney`]                           | MONEY                                                |\n//! | [`PgLTree`]                           | LTREE                                                |\n//! | [`PgLQuery`]                          | LQUERY                                               |\n//! | [`PgCiText`]                          | CITEXT<sup>1</sup>                                   |\n//! | [`PgCube`]                            | CUBE                                                 |\n//! | [`PgPoint`]                           | POINT                                                |\n//! | [`PgLine`]                            | LINE                                                 |\n//! | [`PgLSeg`]                            | LSEG                                                 |\n//! | [`PgBox`]                             | BOX                                                  |\n//! | [`PgPath`]                            | PATH                                                 |\n//! | [`PgPolygon`]                         | POLYGON                                              |\n//! | [`PgCircle`]                          | CIRCLE                                               |\n//! | [`PgHstore`]                          | HSTORE                                               |\n//!\n//! <sup>1</sup> SQLx generally considers `CITEXT` to be compatible with `String`, `&str`, etc.,\n//! but this wrapper type is available for edge cases, such as `CITEXT[]` which Postgres\n//! does not consider to be compatible with `TEXT[]`.\n//!\n//! ### [`bigdecimal`](https://crates.io/crates/bigdecimal)\n//! Requires the `bigdecimal` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                        |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bigdecimal::BigDecimal`              | NUMERIC                                              |\n//!\n#![doc=include_str!(\"bigdecimal-range.md\")]\n//!\n//! ### [`rust_decimal`](https://crates.io/crates/rust_decimal)\n//! Requires the `rust_decimal` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                        |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `rust_decimal::Decimal`               | NUMERIC                                              |\n//!\n#![doc=include_str!(\"rust_decimal-range.md\")]\n//!\n//! ### [`chrono`](https://crates.io/crates/chrono)\n//!\n//! Requires the `chrono` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `chrono::DateTime<Utc>`               | TIMESTAMPTZ                                          |\n//! | `chrono::DateTime<Local>`             | TIMESTAMPTZ                                          |\n//! | `chrono::NaiveDateTime`               | TIMESTAMP                                            |\n//! | `chrono::NaiveDate`                   | DATE                                                 |\n//! | `chrono::NaiveTime`                   | TIME                                                 |\n//! | [`PgTimeTz`]                          | TIMETZ                                               |\n//!\n//! ### [`time`](https://crates.io/crates/time)\n//!\n//! Requires the `time` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `time::PrimitiveDateTime`             | TIMESTAMP                                            |\n//! | `time::OffsetDateTime`                | TIMESTAMPTZ                                          |\n//! | `time::Date`                          | DATE                                                 |\n//! | `time::Time`                          | TIME                                                 |\n//! | [`PgTimeTz`]                          | TIMETZ                                               |\n//!\n//! ### [`uuid`](https://crates.io/crates/uuid)\n//!\n//! Requires the `uuid` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `uuid::Uuid`                          | UUID                                                 |\n//!\n//! ### [`ipnetwork`](https://crates.io/crates/ipnetwork)\n//!\n//! Requires the `ipnetwork` Cargo feature flag (takes precedence over `ipnet` if both are used).\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `ipnetwork::IpNetwork`                | INET, CIDR                                           |\n//! | `std::net::IpAddr`                    | INET, CIDR                                           |\n//!\n//! Note that because `IpAddr` does not support network prefixes, it is an error to attempt to decode\n//! an `IpAddr` from a `INET` or `CIDR` value with a network prefix smaller than the address' full width:\n//! `/32` for IPv4 addresses and `/128` for IPv6 addresses.\n//!\n//! `IpNetwork` does not have this limitation.\n//!\n//! ### [`ipnet`](https://crates.io/crates/ipnet)\n//!\n//! Requires the `ipnet` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `ipnet::IpNet`                        | INET, CIDR                                           |\n//! | `std::net::IpAddr`                    | INET, CIDR                                           |\n//!\n//! The same `IpAddr` limitation for smaller network prefixes applies as with `ipnet`.\n//!\n//! ### [`mac_address`](https://crates.io/crates/mac_address)\n//!\n//! Requires the `mac_address` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `mac_address::MacAddress`             | MACADDR                                              |\n//!\n//! ### [`bit-vec`](https://crates.io/crates/bit-vec)\n//!\n//! Requires the `bit-vec` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bit_vec::BitVec`                     | BIT, VARBIT                                          |\n//!\n//! ### [`json`](https://crates.io/crates/serde_json)\n//!\n//! Requires the `json` Cargo feature flag.\n//!\n//! | Rust type                             | Postgres type(s)                                     |\n//! |---------------------------------------|------------------------------------------------------|\n//! | [`Json<T>`]                           | JSON, JSONB                                          |\n//! | `serde_json::Value`                   | JSON, JSONB                                          |\n//! | `&serde_json::value::RawValue`        | JSON, JSONB                                          |\n//!\n//! `Value` and `RawValue` from `serde_json` can be used for unstructured JSON data with\n//! Postgres.\n//!\n//! [`Json<T>`](crate::types::Json) can be used for structured JSON data with Postgres.\n//!\n//! # [Composite types](https://www.postgresql.org/docs/current/rowtypes.html)\n//!\n//! User-defined composite types are supported through a derive for `Type`.\n//!\n//! ```text\n//! CREATE TYPE inventory_item AS (\n//!     name            text,\n//!     supplier_id     integer,\n//!     price           numeric\n//! );\n//! ```\n//!\n//! ```rust,ignore\n//! #[derive(sqlx::Type)]\n//! #[sqlx(type_name = \"inventory_item\")]\n//! struct InventoryItem {\n//!     name: String,\n//!     supplier_id: i32,\n//!     price: BigDecimal,\n//! }\n//! ```\n//!\n//! Anonymous composite types are represented as tuples. Note that anonymous composites may only\n//! be returned and not sent to Postgres (this is a limitation of postgres).\n//!\n//! # Arrays\n//!\n//! One-dimensional arrays are supported as `Vec<T>` or `&[T]` where `T` implements `Type`.\n//!\n//! # [Enumerations](https://www.postgresql.org/docs/current/datatype-enum.html)\n//!\n//! User-defined enumerations are supported through a derive for `Type`.\n//!\n//! ```text\n//! CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');\n//! ```\n//!\n//! ```rust,ignore\n//! #[derive(sqlx::Type)]\n//! #[sqlx(type_name = \"mood\", rename_all = \"lowercase\")]\n//! enum Mood { Sad, Ok, Happy }\n//! ```\n//!\n//! Rust enumerations may also be defined to be represented as an integer using `repr`.\n//! The following type expects a SQL type of `INTEGER` or `INT4` and will convert to/from the\n//! Rust enumeration.\n//!\n//! ```rust,ignore\n//! #[derive(sqlx::Type)]\n//! #[repr(i32)]\n//! enum Mood { Sad = 0, Ok = 1, Happy = 2 }\n//! ```\n//!\n//! Rust enumerations may also be defined to be represented as a string using `type_name = \"text\"`.\n//! The following type expects a SQL type of `TEXT` and will convert to/from the Rust enumeration.\n//!\n//! ```rust,ignore\n//! #[derive(sqlx::Type)]\n//! #[sqlx(type_name = \"text\")]\n//! enum Mood { Sad, Ok, Happy }\n//! ```\n//!\n//! Note that an error can occur if you attempt to decode a value not contained within the enum\n//! definition.\n//!\n\nuse crate::type_info::PgTypeKind;\nuse crate::{PgTypeInfo, Postgres};\n\n#[cfg(feature = \"json\")]\npub(crate) use sqlx_core::types::Json;\npub(crate) use sqlx_core::types::Type;\n\nmod array;\nmod bool;\nmod bytes;\nmod citext;\nmod float;\nmod hstore;\nmod int;\nmod interval;\n#[cfg(feature = \"json\")]\nmod json;\nmod lquery;\nmod ltree;\nmod money;\nmod oid;\nmod range;\nmod record;\nmod str;\nmod text;\nmod tuple;\nmod void;\n\n#[cfg(any(feature = \"chrono\", feature = \"time\"))]\nmod time_tz;\n\n#[cfg(feature = \"bigdecimal\")]\nmod bigdecimal;\n\nmod cube;\n\nmod geometry;\n\n#[cfg(any(feature = \"bigdecimal\", feature = \"rust_decimal\"))]\nmod numeric;\n\n#[cfg(feature = \"rust_decimal\")]\nmod rust_decimal;\n\n#[cfg(feature = \"chrono\")]\nmod chrono;\n\n#[cfg(feature = \"time\")]\nmod time;\n\n#[cfg(feature = \"uuid\")]\nmod uuid;\n\n#[cfg(feature = \"ipnet\")]\nmod ipnet;\n\n#[cfg(feature = \"ipnetwork\")]\nmod ipnetwork;\n\n#[cfg(feature = \"mac_address\")]\nmod mac_address;\n\n#[cfg(feature = \"bit-vec\")]\nmod bit_vec;\n\npub use array::PgHasArrayType;\npub use citext::PgCiText;\npub use cube::PgCube;\npub use geometry::circle::PgCircle;\npub use geometry::line::PgLine;\npub use geometry::line_segment::PgLSeg;\npub use geometry::path::PgPath;\npub use geometry::point::PgPoint;\npub use geometry::polygon::PgPolygon;\npub use geometry::r#box::PgBox;\npub use hstore::PgHstore;\npub use interval::PgInterval;\npub use lquery::PgLQuery;\npub use lquery::PgLQueryLevel;\npub use lquery::PgLQueryVariant;\npub use lquery::PgLQueryVariantFlag;\npub use ltree::PgLTree;\npub use ltree::PgLTreeLabel;\npub use ltree::PgLTreeParseError;\npub use money::PgMoney;\npub use oid::Oid;\npub use range::PgRange;\n\n#[cfg(any(feature = \"chrono\", feature = \"time\"))]\npub use time_tz::PgTimeTz;\n\n// used in derive(Type) for `struct`\n// but the interface is not considered part of the public API\n#[doc(hidden)]\npub use record::{PgRecordDecoder, PgRecordEncoder};\n\n// Type::compatible impl appropriate for arrays\nfn array_compatible<E: Type<Postgres> + ?Sized>(ty: &PgTypeInfo) -> bool {\n    // we require the declared type to be an _array_ with an\n    // element type that is acceptable\n    if let PgTypeKind::Array(element) = &ty.kind() {\n        return E::compatible(element);\n    }\n\n    false\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/money.rs",
    "content": "use crate::{\n    decode::Decode,\n    encode::{Encode, IsNull},\n    error::BoxDynError,\n    types::Type,\n    {PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres},\n};\nuse byteorder::{BigEndian, ByteOrder};\nuse std::{\n    io,\n    ops::{Add, AddAssign, Sub, SubAssign},\n};\n\n/// The PostgreSQL [`MONEY`] type stores a currency amount with a fixed fractional\n/// precision. The fractional precision is determined by the database's\n/// `lc_monetary` setting.\n///\n/// Data is read and written as 64-bit signed integers, and conversion into a\n/// decimal should be done using the right precision.\n///\n/// Reading `MONEY` value in text format is not supported and will cause an error.\n///\n/// ### `locale_frac_digits`\n/// This parameter corresponds to the number of digits after the decimal separator.\n///\n/// This value must match what Postgres is expecting for the locale set in the database\n/// or else the decimal value you see on the client side will not match the `money` value\n/// on the server side.\n///\n/// **For _most_ locales, this value is `2`.**\n///\n/// If you're not sure what locale your database is set to or how many decimal digits it specifies,\n/// you can execute `SHOW lc_monetary;` to get the locale name, and then look it up in this list\n/// (you can ignore the `.utf8` prefix):\n/// <https://lh.2xlibre.net/values/frac_digits/>\n///\n/// If that link is dead and you're on a POSIX-compliant system (Unix, FreeBSD) you can also execute:\n///\n/// ```sh\n/// $ LC_MONETARY=<value returned by `SHOW lc_monetary`> locale -k frac_digits\n/// ```\n///\n/// And the value you want is `N` in `frac_digits=N`. If you have shell access to the database\n/// server you should execute it there as available locales may differ between machines.\n///\n/// Note that if `frac_digits` for the locale is outside the range `[0, 10]`, Postgres assumes\n/// it's a sentinel value and defaults to 2:\n/// <https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/cash.c#L114-L123>\n///\n/// [`MONEY`]: https://www.postgresql.org/docs/current/datatype-money.html\n#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]\npub struct PgMoney(\n    /// The raw integer value sent over the wire; for locales with `frac_digits=2` (i.e. most\n    /// of them), this will be the value in whole cents.\n    ///\n    /// E.g. for `select '$123.45'::money` with a locale of `en_US` (`frac_digits=2`),\n    /// this will be `12345`.\n    ///\n    /// If the currency of your locale does not have fractional units, e.g. Yen, then this will\n    /// just be the units of the currency.\n    ///\n    /// See the type-level docs for an explanation of `locale_frac_units`.\n    pub i64,\n);\n\nimpl PgMoney {\n    /// Convert the money value into a [`BigDecimal`] using `locale_frac_digits`.\n    ///\n    /// See the type-level docs for an explanation of `locale_frac_digits`.\n    ///\n    /// [`BigDecimal`]: bigdecimal::BigDecimal\n    #[cfg(feature = \"bigdecimal\")]\n    pub fn to_bigdecimal(self, locale_frac_digits: i64) -> bigdecimal::BigDecimal {\n        let digits = num_bigint::BigInt::from(self.0);\n\n        bigdecimal::BigDecimal::new(digits, locale_frac_digits)\n    }\n\n    /// Convert the money value into a [`Decimal`] using `locale_frac_digits`.\n    ///\n    /// See the type-level docs for an explanation of `locale_frac_digits`.\n    ///\n    /// [`Decimal`]: rust_decimal::Decimal\n    #[cfg(feature = \"rust_decimal\")]\n    pub fn to_decimal(self, locale_frac_digits: u32) -> rust_decimal::Decimal {\n        rust_decimal::Decimal::new(self.0, locale_frac_digits)\n    }\n\n    /// Convert a [`Decimal`] value into money using `locale_frac_digits`.\n    ///\n    /// See the type-level docs for an explanation of `locale_frac_digits`.\n    ///\n    /// Note that `Decimal` has 96 bits of precision, but `PgMoney` only has 63 plus the sign bit.\n    /// If the value is larger than 63 bits it will be truncated.\n    ///\n    /// [`Decimal`]: rust_decimal::Decimal\n    #[cfg(feature = \"rust_decimal\")]\n    pub fn from_decimal(mut decimal: rust_decimal::Decimal, locale_frac_digits: u32) -> Self {\n        // this is all we need to convert to our expected locale's `frac_digits`\n        decimal.rescale(locale_frac_digits);\n\n        /// a mask to bitwise-AND with an `i64` to zero the sign bit\n        const SIGN_MASK: i64 = i64::MAX;\n\n        let is_negative = decimal.is_sign_negative();\n        let serialized = decimal.serialize();\n\n        // interpret bytes `4..12` as an i64, ignoring the sign bit\n        // this is where truncation occurs\n        let value = i64::from_le_bytes(\n            *<&[u8; 8]>::try_from(&serialized[4..12])\n                .expect(\"BUG: slice of serialized should be 8 bytes\"),\n        ) & SIGN_MASK; // zero out the sign bit\n\n        // negate if necessary\n        Self(if is_negative { -value } else { value })\n    }\n\n    /// Convert a [`BigDecimal`](bigdecimal::BigDecimal) value into money using the correct precision\n    /// defined in the PostgreSQL settings. The default precision is two.\n    #[cfg(feature = \"bigdecimal\")]\n    pub fn from_bigdecimal(\n        decimal: bigdecimal::BigDecimal,\n        locale_frac_digits: u32,\n    ) -> Result<Self, BoxDynError> {\n        use bigdecimal::ToPrimitive;\n\n        let multiplier = bigdecimal::BigDecimal::new(\n            num_bigint::BigInt::from(10i128.pow(locale_frac_digits)),\n            0,\n        );\n\n        let cents = decimal * multiplier;\n\n        let money = cents.to_i64().ok_or_else(|| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"Provided BigDecimal could not convert to i64: overflow.\",\n            )\n        })?;\n\n        Ok(Self(money))\n    }\n}\n\nimpl Type<Postgres> for PgMoney {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::MONEY\n    }\n}\n\nimpl PgHasArrayType for PgMoney {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::MONEY_ARRAY\n    }\n}\n\nimpl<T> From<T> for PgMoney\nwhere\n    T: Into<i64>,\n{\n    fn from(num: T) -> Self {\n        Self(num.into())\n    }\n}\n\nimpl Encode<'_, Postgres> for PgMoney {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.0.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for PgMoney {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => {\n                let cents = BigEndian::read_i64(value.as_bytes()?);\n\n                Ok(PgMoney(cents))\n            }\n            PgValueFormat::Text => {\n                let error = io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    \"Reading a `MONEY` value in text format is not supported.\",\n                );\n\n                Err(Box::new(error))\n            }\n        }\n    }\n}\n\nimpl Add<PgMoney> for PgMoney {\n    type Output = PgMoney;\n\n    /// Adds two monetary values.\n    ///\n    /// # Panics\n    /// Panics if overflowing the `i64::MAX`.\n    fn add(self, rhs: PgMoney) -> Self::Output {\n        self.0\n            .checked_add(rhs.0)\n            .map(PgMoney)\n            .expect(\"overflow adding money amounts\")\n    }\n}\n\nimpl AddAssign<PgMoney> for PgMoney {\n    /// An assigning add for two monetary values.\n    ///\n    /// # Panics\n    /// Panics if overflowing the `i64::MAX`.\n    fn add_assign(&mut self, rhs: PgMoney) {\n        self.0 = self\n            .0\n            .checked_add(rhs.0)\n            .expect(\"overflow adding money amounts\")\n    }\n}\n\nimpl Sub<PgMoney> for PgMoney {\n    type Output = PgMoney;\n\n    /// Subtracts two monetary values.\n    ///\n    /// # Panics\n    /// Panics if underflowing the `i64::MIN`.\n    fn sub(self, rhs: PgMoney) -> Self::Output {\n        self.0\n            .checked_sub(rhs.0)\n            .map(PgMoney)\n            .expect(\"overflow subtracting money amounts\")\n    }\n}\n\nimpl SubAssign<PgMoney> for PgMoney {\n    /// An assigning subtract for two monetary values.\n    ///\n    /// # Panics\n    /// Panics if underflowing the `i64::MIN`.\n    fn sub_assign(&mut self, rhs: PgMoney) {\n        self.0 = self\n            .0\n            .checked_sub(rhs.0)\n            .expect(\"overflow subtracting money amounts\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::PgMoney;\n\n    #[test]\n    fn adding_works() {\n        assert_eq!(PgMoney(3), PgMoney(1) + PgMoney(2))\n    }\n\n    #[test]\n    fn add_assign_works() {\n        let mut money = PgMoney(1);\n        money += PgMoney(2);\n\n        assert_eq!(PgMoney(3), money);\n    }\n\n    #[test]\n    fn subtracting_works() {\n        assert_eq!(PgMoney(4), PgMoney(5) - PgMoney(1))\n    }\n\n    #[test]\n    fn sub_assign_works() {\n        let mut money = PgMoney(1);\n        money -= PgMoney(2);\n\n        assert_eq!(PgMoney(-1), money);\n    }\n\n    #[test]\n    fn default_value() {\n        let money = PgMoney::default();\n\n        assert_eq!(money, PgMoney(0));\n    }\n\n    #[test]\n    #[should_panic]\n    fn add_overflow_panics() {\n        let _ = PgMoney(i64::MAX) + PgMoney(1);\n    }\n\n    #[test]\n    #[should_panic]\n    fn add_assign_overflow_panics() {\n        let mut money = PgMoney(i64::MAX);\n        money += PgMoney(1);\n    }\n\n    #[test]\n    #[should_panic]\n    fn sub_overflow_panics() {\n        let _ = PgMoney(i64::MIN) - PgMoney(1);\n    }\n\n    #[test]\n    #[should_panic]\n    fn sub_assign_overflow_panics() {\n        let mut money = PgMoney(i64::MIN);\n        money -= PgMoney(1);\n    }\n\n    #[test]\n    #[cfg(feature = \"bigdecimal\")]\n    fn conversion_to_bigdecimal_works() {\n        let money = PgMoney(12345);\n\n        assert_eq!(\n            bigdecimal::BigDecimal::new(num_bigint::BigInt::from(12345), 2),\n            money.to_bigdecimal(2)\n        );\n    }\n\n    #[test]\n    #[cfg(feature = \"rust_decimal\")]\n    fn conversion_to_decimal_works() {\n        assert_eq!(\n            rust_decimal::Decimal::new(12345, 2),\n            PgMoney(12345).to_decimal(2)\n        );\n    }\n\n    #[test]\n    #[cfg(feature = \"rust_decimal\")]\n    fn conversion_from_decimal_works() {\n        assert_eq!(\n            PgMoney(12345),\n            PgMoney::from_decimal(rust_decimal::Decimal::new(12345, 2), 2)\n        );\n\n        assert_eq!(\n            PgMoney(12345),\n            PgMoney::from_decimal(rust_decimal::Decimal::new(123450, 3), 2)\n        );\n\n        assert_eq!(\n            PgMoney(-12345),\n            PgMoney::from_decimal(rust_decimal::Decimal::new(-123450, 3), 2)\n        );\n\n        assert_eq!(\n            PgMoney(-12300),\n            PgMoney::from_decimal(rust_decimal::Decimal::new(-123, 0), 2)\n        );\n    }\n\n    #[test]\n    #[cfg(feature = \"bigdecimal\")]\n    fn conversion_from_bigdecimal_works() {\n        let dec = bigdecimal::BigDecimal::new(num_bigint::BigInt::from(12345), 2);\n\n        assert_eq!(PgMoney(12345), PgMoney::from_bigdecimal(dec, 2).unwrap());\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/numeric.rs",
    "content": "use sqlx_core::bytes::Buf;\nuse std::num::Saturating;\n\nuse crate::error::BoxDynError;\nuse crate::PgArgumentBuffer;\n\n/// Represents a `NUMERIC` value in the **Postgres** wire protocol.\n#[derive(Debug, PartialEq, Eq)]\npub(crate) enum PgNumeric {\n    /// Equivalent to the `'NaN'` value in Postgres. The result of, e.g. `1 / 0`.\n    NotANumber,\n\n    /// A populated `NUMERIC` value.\n    ///\n    /// A description of these fields can be found here (although the type being described is the\n    /// version for in-memory calculations, the field names are the same):\n    /// https://github.com/postgres/postgres/blob/bcd1c3630095e48bc3b1eb0fc8e8c8a7c851eba1/src/backend/utils/adt/numeric.c#L224-L269\n    Number {\n        /// The sign of the value: positive (also set for 0 and -0), or negative.\n        sign: PgNumericSign,\n\n        /// The digits of the number in base-10000 with the most significant digit first\n        /// (big-endian).\n        ///\n        /// The length of this vector must not overflow `i16` for the binary protocol.\n        ///\n        /// *Note*: the `Encode` implementation will panic if any digit is `>= 10000`.\n        digits: Vec<i16>,\n\n        /// The scaling factor of the number, such that the value will be interpreted as\n        ///\n        /// ```text\n        ///   digits[0] * 10,000 ^ weight\n        /// + digits[1] * 10,000 ^ (weight - 1)\n        /// ...\n        /// + digits[N] * 10,000 ^ (weight - N) where N = digits.len() - 1\n        /// ```\n        /// May be negative.\n        weight: i16,\n\n        /// How many _decimal_ (base-10) digits following the decimal point to consider in\n        /// arithmetic regardless of how many actually follow the decimal point as determined by\n        /// `weight`--the comment in the Postgres code linked above recommends using this only for\n        /// ignoring unnecessary trailing zeroes (as trimming nonzero digits means reducing the\n        /// precision of the value).\n        ///\n        /// Must be `>= 0`.\n        scale: i16,\n    },\n}\n\n// https://github.com/postgres/postgres/blob/bcd1c3630095e48bc3b1eb0fc8e8c8a7c851eba1/src/backend/utils/adt/numeric.c#L167-L170\nconst SIGN_POS: u16 = 0x0000;\nconst SIGN_NEG: u16 = 0x4000;\nconst SIGN_NAN: u16 = 0xC000; // overflows i16 (C equivalent truncates from integer literal)\n\n/// Possible sign values for [PgNumeric].\n#[derive(Copy, Clone, Debug, PartialEq, Eq)]\n#[repr(u16)]\npub(crate) enum PgNumericSign {\n    Positive = SIGN_POS,\n    Negative = SIGN_NEG,\n}\n\nimpl PgNumericSign {\n    fn try_from_u16(val: u16) -> Result<Self, BoxDynError> {\n        match val {\n            SIGN_POS => Ok(PgNumericSign::Positive),\n            SIGN_NEG => Ok(PgNumericSign::Negative),\n\n            SIGN_NAN => unreachable!(\"sign value for NaN passed to PgNumericSign\"),\n\n            _ => Err(format!(\"invalid value for PgNumericSign: {val:#04X}\").into()),\n        }\n    }\n}\n\nimpl PgNumeric {\n    /// Equivalent value of `0::numeric`.\n    pub const ZERO: Self = PgNumeric::Number {\n        sign: PgNumericSign::Positive,\n        digits: vec![],\n        weight: 0,\n        scale: 0,\n    };\n\n    pub(crate) fn is_valid_digit(digit: i16) -> bool {\n        (0..10_000).contains(&digit)\n    }\n\n    pub(crate) fn size_hint(decimal_digits: u64) -> usize {\n        let mut size_hint = Saturating(decimal_digits);\n\n        // BigDecimal::digits() gives us base-10 digits, so we divide by 4 to get base-10000 digits\n        // and since this is just a hint we just always round up\n        size_hint /= 4;\n        size_hint += 1;\n\n        // Times two bytes for each base-10000 digit\n        size_hint *= 2;\n\n        // Plus `weight` and `scale`\n        size_hint += 8;\n\n        usize::try_from(size_hint.0).unwrap_or(usize::MAX)\n    }\n\n    pub(crate) fn decode(mut buf: &[u8]) -> Result<Self, BoxDynError> {\n        // https://github.com/postgres/postgres/blob/bcd1c3630095e48bc3b1eb0fc8e8c8a7c851eba1/src/backend/utils/adt/numeric.c#L874\n        let num_digits = buf.get_u16();\n        let weight = buf.get_i16();\n        let sign = buf.get_u16();\n        let scale = buf.get_i16();\n\n        if sign == SIGN_NAN {\n            Ok(PgNumeric::NotANumber)\n        } else {\n            let digits: Vec<_> = (0..num_digits).map(|_| buf.get_i16()).collect::<_>();\n\n            Ok(PgNumeric::Number {\n                sign: PgNumericSign::try_from_u16(sign)?,\n                scale,\n                weight,\n                digits,\n            })\n        }\n    }\n\n    /// ### Errors\n    ///\n    /// * If `digits.len()` overflows `i16`\n    /// * If any element in `digits` is greater than or equal to 10000\n    pub(crate) fn encode(&self, buf: &mut PgArgumentBuffer) -> Result<(), String> {\n        match *self {\n            PgNumeric::Number {\n                ref digits,\n                sign,\n                scale,\n                weight,\n            } => {\n                let digits_len = i16::try_from(digits.len()).map_err(|_| {\n                    format!(\n                        \"PgNumeric digits.len() ({}) should not overflow i16\",\n                        digits.len()\n                    )\n                })?;\n\n                buf.extend(&digits_len.to_be_bytes());\n                buf.extend(&weight.to_be_bytes());\n                buf.extend(&(sign as i16).to_be_bytes());\n                buf.extend(&scale.to_be_bytes());\n\n                for (i, &digit) in digits.iter().enumerate() {\n                    if !Self::is_valid_digit(digit) {\n                        return Err(format!(\"{i}th PgNumeric digit out of range: {digit}\"));\n                    }\n\n                    buf.extend(&digit.to_be_bytes());\n                }\n            }\n\n            PgNumeric::NotANumber => {\n                buf.extend(&0_i16.to_be_bytes());\n                buf.extend(&0_i16.to_be_bytes());\n                buf.extend(&SIGN_NAN.to_be_bytes());\n                buf.extend(&0_i16.to_be_bytes());\n            }\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/oid.rs",
    "content": "use byteorder::{BigEndian, ByteOrder};\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n/// The PostgreSQL [`OID`] type stores an object identifier,\n/// used internally by PostgreSQL as primary keys for various system tables.\n///\n/// [`OID`]: https://www.postgresql.org/docs/current/datatype-oid.html\n#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)]\npub struct Oid(\n    /// The raw unsigned integer value sent over the wire\n    pub u32,\n);\n\nimpl Type<Postgres> for Oid {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::OID\n    }\n}\n\nimpl PgHasArrayType for Oid {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::OID_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for Oid {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(&self.0.to_be_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for Oid {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(Self(match value.format() {\n            PgValueFormat::Binary => BigEndian::read_u32(value.as_bytes()?),\n            PgValueFormat::Text => value.as_str()?.parse()?,\n        }))\n    }\n}\n\n#[cfg(feature = \"offline\")]\nimpl serde::Serialize for Oid {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: serde::Serializer,\n    {\n        self.0.serialize(serializer)\n    }\n}\n\n#[cfg(feature = \"offline\")]\nimpl<'de> serde::Deserialize<'de> for Oid {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: serde::Deserializer<'de>,\n    {\n        u32::deserialize(deserializer).map(Self)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/range.rs",
    "content": "use std::fmt::{self, Debug, Display, Formatter};\nuse std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeInclusive, RangeTo, RangeToInclusive};\n\nuse bitflags::bitflags;\nuse sqlx_core::bytes::Buf;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::PgTypeKind;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n// https://github.com/postgres/postgres/blob/2f48ede080f42b97b594fb14102c82ca1001b80c/src/include/utils/rangetypes.h#L35-L44\nbitflags! {\n    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\n    struct RangeFlags: u8 {\n        const EMPTY = 0x01;\n        const LB_INC = 0x02;\n        const UB_INC = 0x04;\n        const LB_INF = 0x08;\n        const UB_INF = 0x10;\n        const LB_NULL = 0x20; // not used\n        const UB_NULL = 0x40; // not used\n        const CONTAIN_EMPTY = 0x80; // internal\n    }\n}\n\n#[derive(Debug, PartialEq, Eq, Clone, Copy)]\npub struct PgRange<T> {\n    pub start: Bound<T>,\n    pub end: Bound<T>,\n}\n\nimpl<T> From<[Bound<T>; 2]> for PgRange<T> {\n    fn from(v: [Bound<T>; 2]) -> Self {\n        let [start, end] = v;\n        Self { start, end }\n    }\n}\n\nimpl<T> From<(Bound<T>, Bound<T>)> for PgRange<T> {\n    fn from(v: (Bound<T>, Bound<T>)) -> Self {\n        Self {\n            start: v.0,\n            end: v.1,\n        }\n    }\n}\n\nimpl<T> From<Range<T>> for PgRange<T> {\n    fn from(v: Range<T>) -> Self {\n        Self {\n            start: Bound::Included(v.start),\n            end: Bound::Excluded(v.end),\n        }\n    }\n}\n\nimpl<T> From<RangeFrom<T>> for PgRange<T> {\n    fn from(v: RangeFrom<T>) -> Self {\n        Self {\n            start: Bound::Included(v.start),\n            end: Bound::Unbounded,\n        }\n    }\n}\n\nimpl<T> From<RangeInclusive<T>> for PgRange<T> {\n    fn from(v: RangeInclusive<T>) -> Self {\n        let (start, end) = v.into_inner();\n        Self {\n            start: Bound::Included(start),\n            end: Bound::Included(end),\n        }\n    }\n}\n\nimpl<T> From<RangeTo<T>> for PgRange<T> {\n    fn from(v: RangeTo<T>) -> Self {\n        Self {\n            start: Bound::Unbounded,\n            end: Bound::Excluded(v.end),\n        }\n    }\n}\n\nimpl<T> From<RangeToInclusive<T>> for PgRange<T> {\n    fn from(v: RangeToInclusive<T>) -> Self {\n        Self {\n            start: Bound::Unbounded,\n            end: Bound::Included(v.end),\n        }\n    }\n}\n\nimpl<T> RangeBounds<T> for PgRange<T> {\n    fn start_bound(&self) -> Bound<&T> {\n        match self.start {\n            Bound::Included(ref start) => Bound::Included(start),\n            Bound::Excluded(ref start) => Bound::Excluded(start),\n            Bound::Unbounded => Bound::Unbounded,\n        }\n    }\n\n    fn end_bound(&self) -> Bound<&T> {\n        match self.end {\n            Bound::Included(ref end) => Bound::Included(end),\n            Bound::Excluded(ref end) => Bound::Excluded(end),\n            Bound::Unbounded => Bound::Unbounded,\n        }\n    }\n}\n\nimpl Type<Postgres> for PgRange<i32> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INT4_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<i32>(ty)\n    }\n}\n\nimpl Type<Postgres> for PgRange<i64> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::INT8_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<i64>(ty)\n    }\n}\n\n#[cfg(feature = \"bigdecimal\")]\nimpl Type<Postgres> for PgRange<bigdecimal::BigDecimal> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::NUM_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<bigdecimal::BigDecimal>(ty)\n    }\n}\n\n#[cfg(feature = \"rust_decimal\")]\nimpl Type<Postgres> for PgRange<rust_decimal::Decimal> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::NUM_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<rust_decimal::Decimal>(ty)\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl Type<Postgres> for PgRange<chrono::NaiveDate> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<chrono::NaiveDate>(ty)\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl Type<Postgres> for PgRange<chrono::NaiveDateTime> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TS_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<chrono::NaiveDateTime>(ty)\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl<Tz: chrono::TimeZone> Type<Postgres> for PgRange<chrono::DateTime<Tz>> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TSTZ_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<chrono::DateTime<Tz>>(ty)\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl Type<Postgres> for PgRange<time::Date> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<time::Date>(ty)\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl Type<Postgres> for PgRange<time::PrimitiveDateTime> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TS_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<time::PrimitiveDateTime>(ty)\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl Type<Postgres> for PgRange<time::OffsetDateTime> {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TSTZ_RANGE\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        range_compatible::<time::OffsetDateTime>(ty)\n    }\n}\n\nimpl PgHasArrayType for PgRange<i32> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT4_RANGE_ARRAY\n    }\n}\n\nimpl PgHasArrayType for PgRange<i64> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::INT8_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"bigdecimal\")]\nimpl PgHasArrayType for PgRange<bigdecimal::BigDecimal> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::NUM_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"rust_decimal\")]\nimpl PgHasArrayType for PgRange<rust_decimal::Decimal> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::NUM_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl PgHasArrayType for PgRange<chrono::NaiveDate> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl PgHasArrayType for PgRange<chrono::NaiveDateTime> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TS_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nimpl<Tz: chrono::TimeZone> PgHasArrayType for PgRange<chrono::DateTime<Tz>> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TSTZ_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl PgHasArrayType for PgRange<time::Date> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl PgHasArrayType for PgRange<time::PrimitiveDateTime> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TS_RANGE_ARRAY\n    }\n}\n\n#[cfg(feature = \"time\")]\nimpl PgHasArrayType for PgRange<time::OffsetDateTime> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TSTZ_RANGE_ARRAY\n    }\n}\n\nimpl<'q, T> Encode<'q, Postgres> for PgRange<T>\nwhere\n    T: Encode<'q, Postgres>,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // https://github.com/postgres/postgres/blob/2f48ede080f42b97b594fb14102c82ca1001b80c/src/backend/utils/adt/rangetypes.c#L245\n\n        let mut flags = RangeFlags::empty();\n\n        flags |= match self.start {\n            Bound::Included(_) => RangeFlags::LB_INC,\n            Bound::Unbounded => RangeFlags::LB_INF,\n            Bound::Excluded(_) => RangeFlags::empty(),\n        };\n\n        flags |= match self.end {\n            Bound::Included(_) => RangeFlags::UB_INC,\n            Bound::Unbounded => RangeFlags::UB_INF,\n            Bound::Excluded(_) => RangeFlags::empty(),\n        };\n\n        buf.push(flags.bits());\n\n        if let Bound::Included(v) | Bound::Excluded(v) = &self.start {\n            buf.encode(v)?;\n        }\n\n        if let Bound::Included(v) | Bound::Excluded(v) = &self.end {\n            buf.encode(v)?;\n        }\n\n        // ranges are themselves never null\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r, T> Decode<'r, Postgres> for PgRange<T>\nwhere\n    T: Type<Postgres> + for<'a> Decode<'a, Postgres>,\n{\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        match value.format {\n            PgValueFormat::Binary => {\n                let element_ty = if let PgTypeKind::Range(element) = &value.type_info.0.kind() {\n                    element\n                } else {\n                    return Err(format!(\"unexpected non-range type {}\", value.type_info).into());\n                };\n\n                let mut buf = value.as_bytes()?;\n\n                let mut start = Bound::Unbounded;\n                let mut end = Bound::Unbounded;\n\n                let flags = RangeFlags::from_bits_truncate(buf.get_u8());\n\n                if flags.contains(RangeFlags::EMPTY) {\n                    return Ok(PgRange { start, end });\n                }\n\n                if !flags.contains(RangeFlags::LB_INF) {\n                    let value =\n                        T::decode(PgValueRef::get(&mut buf, value.format, element_ty.clone())?)?;\n\n                    start = if flags.contains(RangeFlags::LB_INC) {\n                        Bound::Included(value)\n                    } else {\n                        Bound::Excluded(value)\n                    };\n                }\n\n                if !flags.contains(RangeFlags::UB_INF) {\n                    let value =\n                        T::decode(PgValueRef::get(&mut buf, value.format, element_ty.clone())?)?;\n\n                    end = if flags.contains(RangeFlags::UB_INC) {\n                        Bound::Included(value)\n                    } else {\n                        Bound::Excluded(value)\n                    };\n                }\n\n                Ok(PgRange { start, end })\n            }\n\n            PgValueFormat::Text => {\n                // https://github.com/postgres/postgres/blob/2f48ede080f42b97b594fb14102c82ca1001b80c/src/backend/utils/adt/rangetypes.c#L2046\n\n                let mut start = None;\n                let mut end = None;\n\n                let s = value.as_str()?;\n\n                // remember the bounds\n                let sb = s.as_bytes();\n                let lower = sb[0] as char;\n                let upper = sb[sb.len() - 1] as char;\n\n                // trim the wrapping braces/brackets\n                let s = &s[1..(s.len() - 1)];\n\n                let mut chars = s.chars();\n\n                let mut element = String::new();\n                let mut done = false;\n                let mut quoted = false;\n                let mut in_quotes = false;\n                let mut in_escape = false;\n                let mut prev_ch = '\\0';\n                let mut count = 0;\n\n                while !done {\n                    element.clear();\n\n                    loop {\n                        match chars.next() {\n                            Some(ch) => {\n                                match ch {\n                                    _ if in_escape => {\n                                        element.push(ch);\n                                        in_escape = false;\n                                    }\n\n                                    '\"' if in_quotes => {\n                                        in_quotes = false;\n                                    }\n\n                                    '\"' => {\n                                        in_quotes = true;\n                                        quoted = true;\n\n                                        if prev_ch == '\"' {\n                                            element.push('\"')\n                                        }\n                                    }\n\n                                    '\\\\' if !in_escape => {\n                                        in_escape = true;\n                                    }\n\n                                    ',' if !in_quotes => break,\n\n                                    _ => {\n                                        element.push(ch);\n                                    }\n                                }\n                                prev_ch = ch;\n                            }\n\n                            None => {\n                                done = true;\n                                break;\n                            }\n                        }\n                    }\n\n                    count += 1;\n                    if !element.is_empty() || quoted {\n                        let value = Some(T::decode(PgValueRef {\n                            type_info: T::type_info(),\n                            format: PgValueFormat::Text,\n                            value: Some(element.as_bytes()),\n                            row: None,\n                        })?);\n\n                        if count == 1 {\n                            start = value;\n                        } else if count == 2 {\n                            end = value;\n                        } else {\n                            return Err(\"more than 2 elements found in a range\".into());\n                        }\n                    }\n                }\n\n                let start = parse_bound(lower, start)?;\n                let end = parse_bound(upper, end)?;\n\n                Ok(PgRange { start, end })\n            }\n        }\n    }\n}\n\nfn parse_bound<T>(ch: char, value: Option<T>) -> Result<Bound<T>, BoxDynError> {\n    Ok(if let Some(value) = value {\n        match ch {\n            '(' | ')' => Bound::Excluded(value),\n            '[' | ']' => Bound::Included(value),\n\n            _ => {\n                return Err(format!(\n                    \"expected `(`, ')', '[', or `]` but found `{ch}` for range literal\"\n                )\n                .into());\n            }\n        }\n    } else {\n        Bound::Unbounded\n    })\n}\n\nimpl<T> Display for PgRange<T>\nwhere\n    T: Display,\n{\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        match &self.start {\n            Bound::Unbounded => f.write_str(\"(,\")?,\n            Bound::Excluded(v) => write!(f, \"({v},\")?,\n            Bound::Included(v) => write!(f, \"[{v},\")?,\n        }\n\n        match &self.end {\n            Bound::Unbounded => f.write_str(\")\")?,\n            Bound::Excluded(v) => write!(f, \"{v})\")?,\n            Bound::Included(v) => write!(f, \"{v}]\")?,\n        }\n\n        Ok(())\n    }\n}\n\nfn range_compatible<E: Type<Postgres>>(ty: &PgTypeInfo) -> bool {\n    // we require the declared type to be a _range_ with an\n    // element type that is acceptable\n    if let PgTypeKind::Range(element) = &ty.kind() {\n        return E::compatible(element);\n    }\n\n    false\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/record.rs",
    "content": "use sqlx_core::bytes::Buf;\n\nuse crate::decode::Decode;\nuse crate::encode::Encode;\nuse crate::error::{mismatched_types, BoxDynError};\nuse crate::type_info::TypeInfo;\nuse crate::type_info::{PgType, PgTypeKind};\nuse crate::types::Oid;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\n#[doc(hidden)]\npub struct PgRecordEncoder<'a> {\n    buf: &'a mut PgArgumentBuffer,\n    off: usize,\n    num: u32,\n}\n\nimpl<'a> PgRecordEncoder<'a> {\n    #[doc(hidden)]\n    pub fn new(buf: &'a mut PgArgumentBuffer) -> Self {\n        let off = buf.len();\n\n        // reserve space for a field count\n        buf.extend(&(0_u32).to_be_bytes());\n\n        Self { buf, off, num: 0 }\n    }\n\n    #[doc(hidden)]\n    pub fn finish(&mut self) {\n        // fill in the record length\n        self.buf[self.off..(self.off + 4)].copy_from_slice(&self.num.to_be_bytes());\n    }\n\n    #[doc(hidden)]\n    pub fn encode<'q, T>(&mut self, value: T) -> Result<&mut Self, BoxDynError>\n    where\n        'a: 'q,\n        T: Encode<'q, Postgres> + Type<Postgres>,\n    {\n        let ty = value.produces().unwrap_or_else(T::type_info);\n\n        match ty.0 {\n            // push a hole for this type ID\n            // to be filled in on query execution\n            PgType::DeclareWithName(name) => self.buf.patch_type_by_name(&name),\n            PgType::DeclareArrayOf(array) => self.buf.patch_array_type(array),\n            // write type id\n            pg_type => self.buf.extend(&pg_type.oid().0.to_be_bytes()),\n        }\n\n        self.buf.encode(value)?;\n        self.num += 1;\n\n        Ok(self)\n    }\n}\n\n#[doc(hidden)]\npub struct PgRecordDecoder<'r> {\n    buf: &'r [u8],\n    typ: PgTypeInfo,\n    fmt: PgValueFormat,\n    ind: usize,\n}\n\nimpl<'r> PgRecordDecoder<'r> {\n    #[doc(hidden)]\n    pub fn new(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let fmt = value.format();\n        let mut buf = value.as_bytes()?;\n        let typ = value.type_info;\n\n        match fmt {\n            PgValueFormat::Binary => {\n                let _len = buf.get_u32();\n            }\n\n            PgValueFormat::Text => {\n                // remove the enclosing `(` .. `)`\n                buf = &buf[1..(buf.len() - 1)];\n            }\n        }\n\n        Ok(Self {\n            buf,\n            fmt,\n            typ,\n            ind: 0,\n        })\n    }\n\n    #[doc(hidden)]\n    pub fn try_decode<T>(&mut self) -> Result<T, BoxDynError>\n    where\n        T: for<'a> Decode<'a, Postgres> + Type<Postgres>,\n    {\n        if self.buf.is_empty() {\n            return Err(format!(\"no field `{0}` found on record\", self.ind).into());\n        }\n\n        match self.fmt {\n            PgValueFormat::Binary => {\n                let element_type_oid = Oid(self.buf.get_u32());\n                let element_type_opt = self.find_type_info(&self.typ, element_type_oid)?;\n\n                if let Some(ty) = &element_type_opt {\n                    if !ty.is_null() && !T::compatible(ty) {\n                        return Err(mismatched_types::<Postgres, T>(ty));\n                    }\n                }\n\n                let element_type =\n                    element_type_opt\n                        .ok_or_else(|| BoxDynError::from(format!(\"custom types in records are not fully supported yet: failed to retrieve type info for field {} with type oid {}\", self.ind, element_type_oid.0)))?;\n\n                self.ind += 1;\n\n                T::decode(PgValueRef::get(&mut self.buf, self.fmt, element_type)?)\n            }\n\n            PgValueFormat::Text => {\n                let mut element = String::new();\n                let mut quoted = false;\n                let mut in_quotes = false;\n                let mut in_escape = false;\n                let mut prev_ch = '\\0';\n\n                while !self.buf.is_empty() {\n                    let ch = self.buf.get_u8() as char;\n                    match ch {\n                        _ if in_escape => {\n                            element.push(ch);\n                            in_escape = false;\n                        }\n\n                        '\"' if in_quotes => {\n                            in_quotes = false;\n                        }\n\n                        '\"' => {\n                            in_quotes = true;\n                            quoted = true;\n\n                            if prev_ch == '\"' {\n                                element.push('\"')\n                            }\n                        }\n\n                        '\\\\' if !in_escape => {\n                            in_escape = true;\n                        }\n\n                        ',' if !in_quotes => break,\n\n                        _ => {\n                            element.push(ch);\n                        }\n                    }\n                    prev_ch = ch;\n                }\n\n                let buf = if element.is_empty() && !quoted {\n                    // completely empty input means NULL\n                    None\n                } else {\n                    Some(element.as_bytes())\n                };\n\n                // NOTE: we do not call [`accepts`] or give a chance to from a user as\n                //       TEXT sequences are not strongly typed\n\n                T::decode(PgValueRef {\n                    // NOTE: We pass `0` as the type ID because we don't have a reasonable value\n                    //       we could use.\n                    type_info: PgTypeInfo::with_oid(Oid(0)),\n                    format: self.fmt,\n                    value: buf,\n                    row: None,\n                })\n            }\n        }\n    }\n\n    fn find_type_info(\n        &self,\n        typ: &PgTypeInfo,\n        oid: Oid,\n    ) -> Result<Option<PgTypeInfo>, BoxDynError> {\n        match typ.kind() {\n            PgTypeKind::Simple if typ.0 == PgType::Record => Ok(PgTypeInfo::try_from_oid(oid)),\n            PgTypeKind::Composite(fields) => {\n                let ty = fields[self.ind].1.clone();\n                if ty.0.oid() != oid {\n                    return Err(\"unexpected mismatch of composite type information\".into());\n                }\n\n                Ok(Some(ty))\n            }\n            PgTypeKind::Domain(domain) => self.find_type_info(domain, oid),\n            _ => Err(\"unexpected custom type being decoded as a composite type\".into()),\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/rust_decimal-range.md",
    "content": "#### Note: `rust_decimal::Decimal` Has a Smaller Range than `NUMERIC`\n`NUMERIC` is can have up to 131,072 digits before the decimal point, and 16,384 digits after it. \nSee [Section 8.1, Numeric Types] of the Postgres manual for details.\n\nHowever, `rust_decimal::Decimal` is limited to a maximum absolute magnitude of 2<sup>96</sup> - 1, \na number with 67 decimal digits, and a minimum absolute magnitude of 10<sup>-28</sup>, a number with, unsurprisingly,\n28 decimal digits.\n\nThus, in contrast with `BigDecimal`, `NUMERIC` can actually represent every possible value of `rust_decimal::Decimal`,\nbut not the other way around. This means that encoding should never fail, but decoding can.\n"
  },
  {
    "path": "sqlx-postgres/src/types/rust_decimal.rs",
    "content": "use rust_decimal::Decimal;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::numeric::{PgNumeric, PgNumericSign};\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nuse rust_decimal::MathematicalOps;\n\nimpl Type<Postgres> for Decimal {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::NUMERIC\n    }\n}\n\nimpl PgHasArrayType for Decimal {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::NUMERIC_ARRAY\n    }\n}\n\nimpl TryFrom<PgNumeric> for Decimal {\n    type Error = BoxDynError;\n\n    fn try_from(numeric: PgNumeric) -> Result<Self, BoxDynError> {\n        Decimal::try_from(&numeric)\n    }\n}\n\nimpl TryFrom<&'_ PgNumeric> for Decimal {\n    type Error = BoxDynError;\n\n    fn try_from(numeric: &'_ PgNumeric) -> Result<Self, BoxDynError> {\n        let (digits, sign, mut weight, scale) = match *numeric {\n            PgNumeric::Number {\n                ref digits,\n                sign,\n                weight,\n                scale,\n            } => (digits, sign, weight, scale),\n\n            PgNumeric::NotANumber => {\n                return Err(\"Decimal does not support NaN values\".into());\n            }\n        };\n\n        if digits.is_empty() {\n            // Postgres returns an empty digit array for 0\n            return Ok(Decimal::ZERO);\n        }\n\n        let scale = u32::try_from(scale)\n            .map_err(|_| format!(\"invalid scale value for Pg NUMERIC: {scale}\"))?;\n\n        let mut value = Decimal::ZERO;\n\n        // Sum over `digits`, multiply each by its weight and add it to `value`.\n        for &digit in digits {\n            let mul = Decimal::from(10_000i16)\n                .checked_powi(weight as i64)\n                .ok_or(\"value not representable as rust_decimal::Decimal\")?;\n\n            let part = Decimal::from(digit)\n                .checked_mul(mul)\n                .ok_or(\"value not representable as rust_decimal::Decimal\")?;\n\n            value = value\n                .checked_add(part)\n                .ok_or(\"value not representable as rust_decimal::Decimal\")?;\n\n            weight = weight.checked_sub(1).ok_or(\"weight underflowed\")?;\n        }\n\n        match sign {\n            PgNumericSign::Positive => value.set_sign_positive(true),\n            PgNumericSign::Negative => value.set_sign_negative(true),\n        }\n\n        value.rescale(scale);\n\n        Ok(value)\n    }\n}\n\nimpl From<Decimal> for PgNumeric {\n    fn from(value: Decimal) -> Self {\n        PgNumeric::from(&value)\n    }\n}\n\n// This impl is effectively infallible because `NUMERIC` has a greater range than `Decimal`.\nimpl From<&'_ Decimal> for PgNumeric {\n    // Impl has been manually validated.\n    #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]\n    fn from(decimal: &Decimal) -> Self {\n        if Decimal::is_zero(decimal) {\n            return PgNumeric::ZERO;\n        }\n\n        assert!(\n            (0u32..=28).contains(&decimal.scale()),\n            \"decimal scale out of range {:?}\",\n            decimal.unpack(),\n        );\n\n        // Cannot overflow: always in the range [0, 28]\n        let scale = decimal.scale() as u16;\n\n        let mut mantissa = decimal.mantissa().unsigned_abs();\n\n        // If our scale is not a multiple of 4, we need to go to the next multiple.\n        let groups_diff = scale % 4;\n        if groups_diff > 0 {\n            let remainder = 4 - groups_diff as u32;\n            let power = 10u32.pow(remainder) as u128;\n\n            // Impossible to overflow; 0 <= mantissa <= 2^96,\n            // and we're multiplying by at most 1,000 (giving us a result < 2^106)\n            mantissa *= power;\n        }\n\n        // Array to store max mantissa of Decimal in Postgres decimal format.\n        let mut digits = Vec::with_capacity(8);\n\n        // Convert to base-10000.\n        while mantissa != 0 {\n            // Cannot overflow or wrap because of the modulus\n            digits.push((mantissa % 10_000) as i16);\n            mantissa /= 10_000;\n        }\n\n        // We started with the low digits first, but they should actually be at the end.\n        digits.reverse();\n\n        // Cannot overflow: strictly smaller than `scale`.\n        let digits_after_decimal = scale.div_ceil(4) as i16;\n\n        // `mantissa` contains at most 29 decimal digits (log10(2^96)),\n        // split into at most 8 4-digit segments.\n        assert!(\n            digits.len() <= 8,\n            \"digits.len() out of range: {}; unpacked: {:?}\",\n            digits.len(),\n            decimal.unpack()\n        );\n\n        // Cannot overflow; at most 8\n        let num_digits = digits.len() as i16;\n\n        // Find how many 4-digit segments should go before the decimal point.\n        // `weight = 0` puts just `digit[0]` before the decimal point, and the rest after.\n        let weight = num_digits - digits_after_decimal - 1;\n\n        // Remove non-significant zeroes.\n        while let Some(&0) = digits.last() {\n            digits.pop();\n        }\n\n        PgNumeric::Number {\n            sign: match decimal.is_sign_negative() {\n                false => PgNumericSign::Positive,\n                true => PgNumericSign::Negative,\n            },\n            // Cannot overflow; between 0 and 28\n            scale: scale as i16,\n            weight,\n            digits,\n        }\n    }\n}\n\nimpl Encode<'_, Postgres> for Decimal {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        PgNumeric::from(self).encode(buf)?;\n\n        Ok(IsNull::No)\n    }\n}\n\n#[doc=include_str!(\"rust_decimal-range.md\")]\nimpl Decode<'_, Postgres> for Decimal {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => PgNumeric::decode(value.as_bytes()?)?.try_into(),\n            PgValueFormat::Text => Ok(value.as_str()?.parse::<Decimal>()?),\n        }\n    }\n}\n\n#[cfg(test)]\n#[allow(clippy::zero_prefixed_literal)] // Used for clarity\nmod tests {\n    use super::{Decimal, PgNumeric, PgNumericSign};\n    use std::convert::TryFrom;\n\n    #[test]\n    fn zero() {\n        let zero: Decimal = \"0\".parse().unwrap();\n\n        assert_eq!(PgNumeric::from(&zero), PgNumeric::ZERO,);\n\n        assert_eq!(Decimal::try_from(&PgNumeric::ZERO).unwrap(), Decimal::ZERO);\n    }\n\n    #[test]\n    fn one() {\n        let one: Decimal = \"1\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&one),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![1]\n            }\n        );\n    }\n\n    #[test]\n    fn ten() {\n        let ten: Decimal = \"10\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&ten),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![10]\n            }\n        );\n    }\n\n    #[test]\n    fn one_hundred() {\n        let one_hundred: Decimal = \"100\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&one_hundred),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![100]\n            }\n        );\n    }\n\n    #[test]\n    fn ten_thousand() {\n        // Decimal doesn't normalize here\n        let ten_thousand: Decimal = \"10000\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&ten_thousand),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 1,\n                digits: vec![1]\n            }\n        );\n    }\n\n    #[test]\n    fn two_digits() {\n        let two_digits: Decimal = \"12345\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&two_digits),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 1,\n                digits: vec![1, 2345]\n            }\n        );\n    }\n\n    #[test]\n    fn one_tenth() {\n        let one_tenth: Decimal = \"0.1\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&one_tenth),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 1,\n                weight: -1,\n                digits: vec![1000]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_1() {\n        let decimal: Decimal = \"1.2345\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&decimal),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 4,\n                weight: 0,\n                digits: vec![1, 2345]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_2() {\n        let decimal: Decimal = \"0.12345\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&decimal),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 5,\n                weight: -1,\n                digits: vec![1234, 5000]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_3() {\n        let decimal: Decimal = \"0.01234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&decimal),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 5,\n                weight: -1,\n                digits: vec![0123, 4000]\n            }\n        );\n    }\n\n    #[test]\n    fn decimal_4() {\n        let decimal: Decimal = \"12345.67890\".parse().unwrap();\n        let expected_numeric = PgNumeric::Number {\n            sign: PgNumericSign::Positive,\n            scale: 5,\n            weight: 1,\n            digits: vec![1, 2345, 6789],\n        };\n        assert_eq!(PgNumeric::from(&decimal), expected_numeric);\n\n        let actual_decimal = Decimal::try_from(expected_numeric).unwrap();\n        assert_eq!(actual_decimal, decimal);\n        assert_eq!(actual_decimal.mantissa(), 1234567890);\n        assert_eq!(actual_decimal.scale(), 5);\n    }\n\n    #[test]\n    fn one_digit_decimal() {\n        let one_digit_decimal: Decimal = \"0.00001234\".parse().unwrap();\n        let expected_numeric = PgNumeric::Number {\n            sign: PgNumericSign::Positive,\n            scale: 8,\n            weight: -2,\n            digits: vec![1234],\n        };\n        assert_eq!(PgNumeric::from(&one_digit_decimal), expected_numeric);\n\n        let actual_decimal = Decimal::try_from(expected_numeric).unwrap();\n        assert_eq!(actual_decimal, one_digit_decimal);\n        assert_eq!(actual_decimal.mantissa(), 1234);\n        assert_eq!(actual_decimal.scale(), 8);\n    }\n\n    #[test]\n    fn max_value() {\n        let expected_numeric = PgNumeric::Number {\n            sign: PgNumericSign::Positive,\n            scale: 0,\n            weight: 7,\n            digits: vec![7, 9228, 1625, 1426, 4337, 5935, 4395, 0335],\n        };\n        assert_eq!(PgNumeric::from(&Decimal::MAX), expected_numeric);\n\n        let actual_decimal = Decimal::try_from(expected_numeric).unwrap();\n        assert_eq!(actual_decimal, Decimal::MAX);\n        // Value split by 10,000's to match the expected digits[]\n        assert_eq!(\n            actual_decimal.mantissa(),\n            7_9228_1625_1426_4337_5935_4395_0335\n        );\n        assert_eq!(actual_decimal.scale(), 0);\n    }\n\n    #[test]\n    fn mult_overflow() {\n        //  -24_0711_6702_1036_7100_2022_8579_3280.00\n        let large_negative_number = PgNumeric::Number {\n            sign: PgNumericSign::Negative,\n            scale: 0,\n            weight: 7,\n            digits: vec![24, 0711, 6702, 1036, 7100, 2022, 8579, 3280],\n        };\n\n        assert!(Decimal::try_from(large_negative_number).is_err());\n    }\n\n    #[test]\n    fn max_value_max_scale() {\n        let mut max_value_max_scale = Decimal::MAX;\n        max_value_max_scale.set_scale(28).unwrap();\n\n        let expected_numeric = PgNumeric::Number {\n            sign: PgNumericSign::Positive,\n            scale: 28,\n            weight: 0,\n            digits: vec![7, 9228, 1625, 1426, 4337, 5935, 4395, 0335],\n        };\n        assert_eq!(PgNumeric::from(&max_value_max_scale), expected_numeric);\n\n        let actual_decimal = Decimal::try_from(expected_numeric).unwrap();\n        assert_eq!(actual_decimal, max_value_max_scale);\n        assert_eq!(\n            actual_decimal.mantissa(),\n            79_228_162_514_264_337_593_543_950_335\n        );\n        assert_eq!(actual_decimal.scale(), 28);\n    }\n\n    #[test]\n    fn issue_423_four_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let four_digit: Decimal = \"1234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&four_digit),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 0,\n                digits: vec![1234]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_negative_four_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let negative_four_digit: Decimal = \"-1234\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&negative_four_digit),\n            PgNumeric::Number {\n                sign: PgNumericSign::Negative,\n                scale: 0,\n                weight: 0,\n                digits: vec![1234]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_eight_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let eight_digit: Decimal = \"12345678\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&eight_digit),\n            PgNumeric::Number {\n                sign: PgNumericSign::Positive,\n                scale: 0,\n                weight: 1,\n                digits: vec![1234, 5678]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_423_negative_eight_digit() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/423\n        let negative_eight_digit: Decimal = \"-12345678\".parse().unwrap();\n        assert_eq!(\n            PgNumeric::from(&negative_eight_digit),\n            PgNumeric::Number {\n                sign: PgNumericSign::Negative,\n                scale: 0,\n                weight: 1,\n                digits: vec![1234, 5678]\n            }\n        );\n    }\n\n    #[test]\n    fn issue_2247_trailing_zeros() {\n        // This is a regression test for https://github.com/launchbadge/sqlx/issues/2247\n        let one_hundred: Decimal = \"100.00\".parse().unwrap();\n        let expected_numeric = PgNumeric::Number {\n            sign: PgNumericSign::Positive,\n            scale: 2,\n            weight: 0,\n            digits: vec![100],\n        };\n        assert_eq!(PgNumeric::from(&one_hundred), expected_numeric);\n\n        let actual_decimal = Decimal::try_from(expected_numeric).unwrap();\n        assert_eq!(actual_decimal, one_hundred);\n        assert_eq!(actual_decimal.mantissa(), 10000);\n        assert_eq!(actual_decimal.scale(), 2);\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/str.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::array_compatible;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nimpl Type<Postgres> for str {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TEXT\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        [\n            PgTypeInfo::TEXT,\n            PgTypeInfo::NAME,\n            PgTypeInfo::BPCHAR,\n            PgTypeInfo::VARCHAR,\n            PgTypeInfo::UNKNOWN,\n            PgTypeInfo::with_name(\"citext\"),\n        ]\n        .contains(ty)\n    }\n}\n\nimpl Type<Postgres> for String {\n    fn type_info() -> PgTypeInfo {\n        <&str as Type<Postgres>>::type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        <&str as Type<Postgres>>::compatible(ty)\n    }\n}\n\nimpl PgHasArrayType for &'_ str {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TEXT_ARRAY\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        array_compatible::<&str>(ty)\n    }\n}\n\nimpl PgHasArrayType for Cow<'_, str> {\n    fn array_type_info() -> PgTypeInfo {\n        <&str as PgHasArrayType>::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        <&str as PgHasArrayType>::array_compatible(ty)\n    }\n}\n\nimpl PgHasArrayType for Box<str> {\n    fn array_type_info() -> PgTypeInfo {\n        <&str as PgHasArrayType>::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        <&str as PgHasArrayType>::array_compatible(ty)\n    }\n}\n\nimpl PgHasArrayType for String {\n    fn array_type_info() -> PgTypeInfo {\n        <&str as PgHasArrayType>::array_type_info()\n    }\n\n    fn array_compatible(ty: &PgTypeInfo) -> bool {\n        <&str as PgHasArrayType>::array_compatible(ty)\n    }\n}\n\nimpl Encode<'_, Postgres> for &'_ str {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend(self.as_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for &'r str {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        value.as_str()\n    }\n}\n\nimpl Decode<'_, Postgres> for String {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        Ok(value.as_str()?.to_owned())\n    }\n}\n\nforward_encode_impl!(Arc<str>, &str, Postgres);\nforward_encode_impl!(Rc<str>, &str, Postgres);\nforward_encode_impl!(Cow<'_, str>, &str, Postgres);\nforward_encode_impl!(Box<str>, &str, Postgres);\nforward_encode_impl!(String, &str, Postgres);\n"
  },
  {
    "path": "sqlx-postgres/src/types/text.rs",
    "content": "use crate::{PgArgumentBuffer, PgTypeInfo, PgValueRef, Postgres};\nuse sqlx_core::decode::Decode;\nuse sqlx_core::encode::{Encode, IsNull};\nuse sqlx_core::error::BoxDynError;\nuse sqlx_core::types::{Text, Type};\nuse std::fmt::Display;\nuse std::str::FromStr;\n\nuse std::io::Write;\n\nimpl<T> Type<Postgres> for Text<T> {\n    fn type_info() -> PgTypeInfo {\n        <String as Type<Postgres>>::type_info()\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        <String as Type<Postgres>>::compatible(ty)\n    }\n}\n\nimpl<T> Encode<'_, Postgres> for Text<T>\nwhere\n    T: Display,\n{\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        write!(**buf, \"{}\", self.0)?;\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r, T> Decode<'r, Postgres> for Text<T>\nwhere\n    T: FromStr,\n    BoxDynError: From<<T as FromStr>::Err>,\n{\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        let s: &str = Decode::<Postgres>::decode(value)?;\n        Ok(Self(s.parse()?))\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/time/date.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::time::PG_EPOCH;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse std::mem;\nuse time::macros::format_description;\nuse time::{Date, Duration};\n\nimpl Type<Postgres> for Date {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE\n    }\n}\n\nimpl PgHasArrayType for Date {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::DATE_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for Date {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // DATE is encoded as number of days since epoch (2000-01-01)\n        let days: i32 = (*self - PG_EPOCH).whole_days().try_into().map_err(|_| {\n            format!(\"value {self:?} would overflow binary encoding for Postgres DATE\")\n        })?;\n        Encode::<Postgres>::encode(days, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i32>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for Date {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                // DATE is encoded as the days since epoch\n                let days: i32 = Decode::<Postgres>::decode(value)?;\n                PG_EPOCH + Duration::days(days.into())\n            }\n\n            PgValueFormat::Text => Date::parse(\n                value.as_str()?,\n                &format_description!(\"[year]-[month]-[day]\"),\n            )?,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/time/datetime.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::time::PG_EPOCH;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse std::borrow::Cow;\nuse std::mem;\nuse time::macros::format_description;\nuse time::macros::offset;\nuse time::{Duration, OffsetDateTime, PrimitiveDateTime};\n\nimpl Type<Postgres> for PrimitiveDateTime {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMP\n    }\n}\n\nimpl Type<Postgres> for OffsetDateTime {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMPTZ\n    }\n}\n\nimpl PgHasArrayType for PrimitiveDateTime {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMP_ARRAY\n    }\n}\n\nimpl PgHasArrayType for OffsetDateTime {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMESTAMPTZ_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for PrimitiveDateTime {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // TIMESTAMP is encoded as the microseconds since the epoch\n        let micros: i64 = (*self - PG_EPOCH.midnight())\n            .whole_microseconds()\n            .try_into()\n            .map_err(|_| {\n                format!(\"value {self:?} would overflow binary encoding for Postgres TIME\")\n            })?;\n        Encode::<Postgres>::encode(micros, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i64>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for PrimitiveDateTime {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                // TIMESTAMP is encoded as the microseconds since the epoch\n                let us = Decode::<Postgres>::decode(value)?;\n                PG_EPOCH.midnight() + Duration::microseconds(us)\n            }\n\n            PgValueFormat::Text => {\n                let s = value.as_str()?;\n\n                // If there is no decimal point we need to add one.\n                let s = if s.contains('.') {\n                    Cow::Borrowed(s)\n                } else {\n                    Cow::Owned(format!(\"{s}.0\"))\n                };\n\n                // Contains a time-zone specifier\n                // This is given for timestamptz for some reason\n                // Postgres already guarantees this to always be UTC\n                if s.contains('+') {\n                    PrimitiveDateTime::parse(&s, &format_description!(\"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond][offset_hour]\"))?\n                } else {\n                    PrimitiveDateTime::parse(\n                        &s,\n                        &format_description!(\n                            \"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]\"\n                        ),\n                    )?\n                }\n            }\n        })\n    }\n}\n\nimpl Encode<'_, Postgres> for OffsetDateTime {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        let utc = self.to_offset(offset!(UTC));\n        let primitive = PrimitiveDateTime::new(utc.date(), utc.time());\n\n        Encode::<Postgres>::encode(primitive, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<i64>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for OffsetDateTime {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(<PrimitiveDateTime as Decode<Postgres>>::decode(value)?.assume_utc())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/time/mod.rs",
    "content": "mod date;\nmod datetime;\n\n// Parent module is named after the `time` crate, this module is named after the `TIME` SQL type.\n#[allow(clippy::module_inception)]\nmod time;\n\n#[rustfmt::skip]\nconst PG_EPOCH: ::time::Date = ::time::macros::date!(2000-1-1);\n"
  },
  {
    "path": "sqlx-postgres/src/types/time/time.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse std::mem;\nuse time::macros::format_description;\nuse time::{Duration, Time};\n\nimpl Type<Postgres> for Time {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::TIME\n    }\n}\n\nimpl PgHasArrayType for Time {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIME_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for Time {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        // TIME is encoded as the microseconds since midnight.\n        //\n        // A truncating cast is fine because `self - Time::MIDNIGHT` cannot exceed a span of 24 hours.\n        #[allow(clippy::cast_possible_truncation)]\n        let micros: i64 = (*self - Time::MIDNIGHT).whole_microseconds() as i64;\n        Encode::<Postgres>::encode(micros, buf)\n    }\n\n    fn size_hint(&self) -> usize {\n        mem::size_of::<u64>()\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for Time {\n    fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(match value.format() {\n            PgValueFormat::Binary => {\n                // TIME is encoded as the microseconds since midnight\n                let us = Decode::<Postgres>::decode(value)?;\n                Time::MIDNIGHT + Duration::microseconds(us)\n            }\n\n            PgValueFormat::Text => Time::parse(\n                value.as_str()?,\n                // Postgres will not include the subsecond part if it's zero.\n                &format_description!(\"[hour]:[minute]:[second][optional [.[subsecond]]]\"),\n            )?,\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/time_tz.rs",
    "content": "use crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\nuse byteorder::{BigEndian, ReadBytesExt};\nuse std::io::Cursor;\nuse std::mem;\n\n#[cfg(feature = \"time\")]\ntype DefaultTime = ::time::Time;\n\n#[cfg(all(not(feature = \"time\"), feature = \"chrono\"))]\ntype DefaultTime = ::chrono::NaiveTime;\n\n#[cfg(feature = \"time\")]\ntype DefaultOffset = ::time::UtcOffset;\n\n#[cfg(all(not(feature = \"time\"), feature = \"chrono\"))]\ntype DefaultOffset = ::chrono::FixedOffset;\n\n/// Represents a moment of time, in a specified timezone.\n///\n/// # Warning\n///\n/// `PgTimeTz` provides `TIMETZ` and is supported only for reading from legacy databases.\n/// [PostgreSQL recommends] to use `TIMESTAMPTZ` instead.\n///\n/// [PostgreSQL recommends]: https://wiki.postgresql.org/wiki/Don't_Do_This#Don.27t_use_timetz\n#[derive(Debug, PartialEq, Clone, Copy)]\npub struct PgTimeTz<Time = DefaultTime, Offset = DefaultOffset> {\n    pub time: Time,\n    pub offset: Offset,\n}\n\nimpl<Time, Offset> PgHasArrayType for PgTimeTz<Time, Offset> {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::TIMETZ_ARRAY\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nmod chrono {\n    use super::*;\n    use ::chrono::{DateTime, Duration, FixedOffset, NaiveTime};\n\n    impl Type<Postgres> for PgTimeTz<NaiveTime, FixedOffset> {\n        fn type_info() -> PgTypeInfo {\n            PgTypeInfo::TIMETZ\n        }\n    }\n\n    impl Encode<'_, Postgres> for PgTimeTz<NaiveTime, FixedOffset> {\n        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n            let _: IsNull = <NaiveTime as Encode<'_, Postgres>>::encode(self.time, buf)?;\n            let _: IsNull =\n                <i32 as Encode<'_, Postgres>>::encode(self.offset.utc_minus_local(), buf)?;\n\n            Ok(IsNull::No)\n        }\n\n        fn size_hint(&self) -> usize {\n            mem::size_of::<i64>() + mem::size_of::<i32>()\n        }\n    }\n\n    impl<'r> Decode<'r, Postgres> for PgTimeTz<NaiveTime, FixedOffset> {\n        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n            match value.format() {\n                PgValueFormat::Binary => {\n                    let mut buf = Cursor::new(value.as_bytes()?);\n\n                    // TIME is encoded as the microseconds since midnight\n                    let us = buf.read_i64::<BigEndian>()?;\n                    // default is midnight, there is a canary test for this\n                    // in `sqlx-postgres/src/types/chrono/time.rs`\n                    let time = NaiveTime::default() + Duration::microseconds(us);\n\n                    // OFFSET is encoded as seconds from UTC\n                    let offset_seconds = buf.read_i32::<BigEndian>()?;\n\n                    let offset = FixedOffset::west_opt(offset_seconds).ok_or_else(|| {\n                        format!(\n                            \"server returned out-of-range offset for `TIMETZ`: {offset_seconds} seconds\"\n                        )\n                    })?;\n\n                    Ok(PgTimeTz { time, offset })\n                }\n\n                PgValueFormat::Text => try_parse_timetz(value.as_str()?),\n            }\n        }\n    }\n\n    fn try_parse_timetz(s: &str) -> Result<PgTimeTz<NaiveTime, FixedOffset>, BoxDynError> {\n        let mut tmp = String::with_capacity(11 + s.len());\n        tmp.push_str(\"2001-07-08 \");\n        tmp.push_str(s);\n\n        let mut err = None;\n\n        for fmt in &[\"%Y-%m-%d %H:%M:%S%.f%#z\", \"%Y-%m-%d %H:%M:%S%.f\"] {\n            match DateTime::parse_from_str(&tmp, fmt) {\n                Ok(dt) => {\n                    let time = dt.time();\n                    let offset = *dt.offset();\n\n                    return Ok(PgTimeTz { time, offset });\n                }\n\n                Err(error) => {\n                    err = Some(error);\n                }\n            }\n        }\n\n        Err(err\n            .expect(\"BUG: loop should have set `err` to `Some()` before exiting\")\n            .into())\n    }\n}\n\n#[cfg(feature = \"time\")]\nmod time {\n    use super::*;\n    use ::time::{Duration, Time, UtcOffset};\n\n    impl Type<Postgres> for PgTimeTz<Time, UtcOffset> {\n        fn type_info() -> PgTypeInfo {\n            PgTypeInfo::TIMETZ\n        }\n    }\n\n    impl Encode<'_, Postgres> for PgTimeTz<Time, UtcOffset> {\n        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n            let _: IsNull = <Time as Encode<'_, Postgres>>::encode(self.time, buf)?;\n            let _: IsNull =\n                <i32 as Encode<'_, Postgres>>::encode(-self.offset.whole_seconds(), buf)?;\n\n            Ok(IsNull::No)\n        }\n\n        fn size_hint(&self) -> usize {\n            mem::size_of::<i64>() + mem::size_of::<i32>()\n        }\n    }\n\n    impl<'r> Decode<'r, Postgres> for PgTimeTz<Time, UtcOffset> {\n        fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n            match value.format() {\n                PgValueFormat::Binary => {\n                    let mut buf = Cursor::new(value.as_bytes()?);\n\n                    // TIME is encoded as the microseconds since midnight\n                    let us = buf.read_i64::<BigEndian>()?;\n                    let time = Time::MIDNIGHT + Duration::microseconds(us);\n\n                    // OFFSET is encoded as seconds from UTC\n                    let seconds = buf.read_i32::<BigEndian>()?;\n\n                    Ok(PgTimeTz {\n                        time,\n                        offset: -UtcOffset::from_whole_seconds(seconds)?,\n                    })\n                }\n\n                PgValueFormat::Text => {\n                    // the `time` crate has a limited ability to parse and can't parse the\n                    // timezone format\n                    Err(\"reading a `TIMETZ` value in text format is not supported.\".into())\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/tuple.rs",
    "content": "use crate::decode::Decode;\nuse crate::error::BoxDynError;\nuse crate::types::PgRecordDecoder;\nuse crate::types::Type;\nuse crate::{PgHasArrayType, PgTypeInfo, PgValueRef, Postgres};\n\nmacro_rules! impl_type_for_tuple {\n    ($( $idx:ident : $T:ident ),*) => {\n        impl<$($T,)*> Type<Postgres> for ($($T,)*) {\n\n\n            #[inline]\n            fn type_info() -> PgTypeInfo {\n                PgTypeInfo::RECORD\n            }\n        }\n\n        impl<$($T,)*> PgHasArrayType for ($($T,)*) {\n\n\n            #[inline]\n            fn array_type_info() -> PgTypeInfo {\n                PgTypeInfo::RECORD_ARRAY\n            }\n        }\n\n        impl<'r, $($T,)*> Decode<'r, Postgres> for ($($T,)*)\n        where\n            $($T: 'r,)*\n            $($T: Type<Postgres>,)*\n            $($T: for<'a> Decode<'a, Postgres>,)*\n        {\n\n\n            fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n                #[allow(unused)]\n                let mut decoder = PgRecordDecoder::new(value)?;\n\n                $(let $idx: $T = decoder.try_decode()?;)*\n\n                Ok(($($idx,)*))\n            }\n        }\n    };\n}\n\nimpl_type_for_tuple!(_1: T1);\n\nimpl_type_for_tuple!(_1: T1, _2: T2);\n\nimpl_type_for_tuple!(_1: T1, _2: T2, _3: T3);\n\nimpl_type_for_tuple!(_1: T1, _2: T2, _3: T3, _4: T4);\n\nimpl_type_for_tuple!(_1: T1, _2: T2, _3: T3, _4: T4, _5: T5);\n\nimpl_type_for_tuple!(_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6);\n\nimpl_type_for_tuple!(_1: T1, _2: T2, _3: T3, _4: T4, _5: T5, _6: T6, _7: T7);\n\nimpl_type_for_tuple!(\n    _1: T1,\n    _2: T2,\n    _3: T3,\n    _4: T4,\n    _5: T5,\n    _6: T6,\n    _7: T7,\n    _8: T8\n);\n\nimpl_type_for_tuple!(\n    _1: T1,\n    _2: T2,\n    _3: T3,\n    _4: T4,\n    _5: T5,\n    _6: T6,\n    _7: T7,\n    _8: T8,\n    _9: T9\n);\n"
  },
  {
    "path": "sqlx-postgres/src/types/uuid.rs",
    "content": "use uuid::Uuid;\n\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgArgumentBuffer, PgHasArrayType, PgTypeInfo, PgValueFormat, PgValueRef, Postgres};\n\nimpl Type<Postgres> for Uuid {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::UUID\n    }\n}\n\nimpl PgHasArrayType for Uuid {\n    fn array_type_info() -> PgTypeInfo {\n        PgTypeInfo::UUID_ARRAY\n    }\n}\n\nimpl Encode<'_, Postgres> for Uuid {\n    fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n        buf.extend_from_slice(self.as_bytes());\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Postgres> for Uuid {\n    fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {\n        match value.format() {\n            PgValueFormat::Binary => Uuid::from_slice(value.as_bytes()?),\n            PgValueFormat::Text => value.as_str()?.parse(),\n        }\n        .map_err(Into::into)\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/types/void.rs",
    "content": "use crate::decode::Decode;\nuse crate::error::BoxDynError;\nuse crate::types::Type;\nuse crate::{PgTypeInfo, PgValueRef, Postgres};\n\nimpl Type<Postgres> for () {\n    fn type_info() -> PgTypeInfo {\n        PgTypeInfo::VOID\n    }\n\n    fn compatible(ty: &PgTypeInfo) -> bool {\n        // RECORD is here so we can support the empty tuple\n        *ty == PgTypeInfo::VOID || *ty == PgTypeInfo::RECORD\n    }\n}\n\nimpl<'r> Decode<'r, Postgres> for () {\n    fn decode(_value: PgValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-postgres/src/value.rs",
    "content": "use crate::error::{BoxDynError, UnexpectedNullError};\nuse crate::{PgTypeInfo, Postgres};\nuse sqlx_core::bytes::{Buf, Bytes};\npub(crate) use sqlx_core::value::{Value, ValueRef};\nuse std::borrow::Cow;\nuse std::str::from_utf8;\n\n#[derive(Debug, Clone, Copy, Eq, PartialEq)]\n#[repr(u8)]\npub enum PgValueFormat {\n    Text = 0,\n    Binary = 1,\n}\n\n/// Implementation of [`ValueRef`] for PostgreSQL.\n#[derive(Clone)]\npub struct PgValueRef<'r> {\n    pub(crate) value: Option<&'r [u8]>,\n    pub(crate) row: Option<&'r Bytes>,\n    pub(crate) type_info: PgTypeInfo,\n    pub(crate) format: PgValueFormat,\n}\n\n/// Implementation of [`Value`] for PostgreSQL.\n#[derive(Clone)]\npub struct PgValue {\n    pub(crate) value: Option<Bytes>,\n    pub(crate) type_info: PgTypeInfo,\n    pub(crate) format: PgValueFormat,\n}\n\nimpl<'r> PgValueRef<'r> {\n    pub(crate) fn get(\n        buf: &mut &'r [u8],\n        format: PgValueFormat,\n        ty: PgTypeInfo,\n    ) -> Result<Self, String> {\n        let element_len = buf.get_i32();\n\n        let element_val = if element_len == -1 {\n            None\n        } else {\n            let element_len: usize = element_len\n                .try_into()\n                .map_err(|_| format!(\"overflow converting element_len ({element_len}) to usize\"))?;\n\n            let val = &buf[..element_len];\n            buf.advance(element_len);\n            Some(val)\n        };\n\n        Ok(PgValueRef {\n            value: element_val,\n            row: None,\n            type_info: ty,\n            format,\n        })\n    }\n\n    pub fn format(&self) -> PgValueFormat {\n        self.format\n    }\n\n    pub fn as_bytes(&self) -> Result<&'r [u8], BoxDynError> {\n        match &self.value {\n            Some(v) => Ok(v),\n            None => Err(UnexpectedNullError.into()),\n        }\n    }\n\n    pub fn as_str(&self) -> Result<&'r str, BoxDynError> {\n        Ok(from_utf8(self.as_bytes()?)?)\n    }\n}\n\nimpl Value for PgValue {\n    type Database = Postgres;\n\n    #[inline]\n    fn as_ref(&self) -> PgValueRef<'_> {\n        PgValueRef {\n            value: self.value.as_deref(),\n            row: None,\n            type_info: self.type_info.clone(),\n            format: self.format,\n        }\n    }\n\n    fn type_info(&self) -> Cow<'_, PgTypeInfo> {\n        Cow::Borrowed(&self.type_info)\n    }\n\n    fn is_null(&self) -> bool {\n        self.value.is_none()\n    }\n}\n\nimpl<'r> ValueRef<'r> for PgValueRef<'r> {\n    type Database = Postgres;\n\n    fn to_owned(&self) -> PgValue {\n        let value = match (self.row, self.value) {\n            (Some(row), Some(value)) => Some(row.slice_ref(value)),\n\n            (None, Some(value)) => Some(Bytes::copy_from_slice(value)),\n\n            _ => None,\n        };\n\n        PgValue {\n            value,\n            format: self.format,\n            type_info: self.type_info.clone(),\n        }\n    }\n\n    fn type_info(&self) -> Cow<'_, PgTypeInfo> {\n        Cow::Borrowed(&self.type_info)\n    }\n\n    fn is_null(&self) -> bool {\n        self.value.is_none()\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/Cargo.toml",
    "content": "[package]\nname = \"sqlx-sqlite\"\ndocumentation = \"https://docs.rs/sqlx\"\ndescription = \"SQLite driver implementation for SQLx. Not for direct use; see the `sqlx` crate for details.\"\nversion.workspace = true\nlicense.workspace = true\nedition.workspace = true\nauthors.workspace = true\nrepository.workspace = true\nrust-version.workspace = true\n\n[features]\nany = [\"sqlx-core/any\"]\njson = [\"sqlx-core/json\", \"serde\"]\noffline = [\"sqlx-core/offline\", \"serde\"]\nmigrate = [\"sqlx-core/migrate\"]\n\n# Type integrations\nchrono = [\"dep:chrono\", \"sqlx-core/chrono\"]\ntime = [\"dep:time\", \"sqlx-core/time\"]\nuuid = [\"dep:uuid\", \"sqlx-core/uuid\"]\n\nregexp = [\"dep:regex\"]\n\n# Conditionally compiled SQLite features\ndeserialize = []\nload-extension = []\npreupdate-hook = [\"libsqlite3-sys/preupdate_hook\"]\nunlock-notify = [\"libsqlite3-sys/unlock_notify\"]\n\nbundled = [\"libsqlite3-sys/bundled\"]\nunbundled = [\"libsqlite3-sys/buildtime_bindgen\"]\n\nsqlx-toml = [\"sqlx-core/sqlx-toml\"]\n\n# Note: currently unused, only to satisfy \"unexpected `cfg` condition\" lint\nbigdecimal = []\nrust_decimal = []\n\n_unstable-all-types = [\n    \"json\", \"chrono\", \"time\", \"uuid\",\n]\n\n_unstable-all-sqlite-features = [\n    \"deserialize\",\n    \"load-extension\",\n    \"preupdate-hook\",\n    \"unlock-notify\",\n]\n\n_unstable-docs = [\n    \"bundled\", \"any\",\n    \"_unstable-all-types\",\n    \"_unstable-all-sqlite-features\"\n]\n\n[dependencies.libsqlite3-sys]\n# See `sqlx-sqlite/src/lib.rs` for details.\nversion = \">=0.30.0, <0.37.0\"\ndefault-features = false\nfeatures = [\n    \"pkg-config\",\n    \"vcpkg\",\n]\n\n[dependencies]\nfutures-core = { version = \"0.3.19\", default-features = false }\nfutures-channel = { version = \"0.3.19\", default-features = false, features = [\"sink\", \"alloc\", \"std\"] }\n# used by the SQLite worker thread to block on the async mutex that locks the database handle\nfutures-executor = { version = \"0.3.19\" }\nfutures-intrusive = \"0.5.0\"\nfutures-util = { version = \"0.3.19\", default-features = false, features = [\"alloc\", \"sink\"] }\n\nchrono = { workspace = true, optional = true }\ntime = { workspace = true, optional = true }\nuuid = { workspace = true, optional = true }\n\nurl = { version = \"2.2.2\" }\npercent-encoding = \"2.1.0\"\nform_urlencoded = \"1.2.2\"\n\nflume = { version = \"0.11.0\", default-features = false, features = [\"async\"] }\n\natoi = \"2.0\"\n\nlog = \"0.4.18\"\ntracing = { version = \"0.1.37\", features = [\"log\"] }\n\nthiserror.workspace = true\n\nserde = { version = \"1.0.145\", features = [\"derive\"], optional = true }\nregex = { version = \"1.5.5\", optional = true }\n\n[dependencies.sqlx-core]\nworkspace = true\n\n[dev-dependencies.sqlx]\n# FIXME: https://github.com/rust-lang/cargo/issues/15622\n# workspace = true\npath = \"..\"\ndefault-features = false\nfeatures = [\"macros\", \"runtime-tokio\", \"tls-none\", \"sqlite\"]\n\n[lints]\nworkspace = true\n\n[package.metadata.docs.rs]\nfeatures = [\"__unstable_docs\"]\n"
  },
  {
    "path": "sqlx-sqlite/src/any.rs",
    "content": "use crate::{\n    Either, Sqlite, SqliteArgumentValue, SqliteArguments, SqliteColumn, SqliteConnectOptions,\n    SqliteConnection, SqliteQueryResult, SqliteRow, SqliteTransactionManager, SqliteTypeInfo,\n};\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::{FutureExt, StreamExt, TryFutureExt, TryStreamExt};\n\nuse sqlx_core::any::{\n    AnyArguments, AnyColumn, AnyConnectOptions, AnyConnectionBackend, AnyQueryResult, AnyRow,\n    AnyStatement, AnyTypeInfo, AnyTypeInfoKind, AnyValueKind,\n};\nuse sqlx_core::sql_str::SqlStr;\n\nuse crate::arguments::SqliteArgumentsBuffer;\nuse crate::type_info::DataType;\nuse sqlx_core::connection::{ConnectOptions, Connection};\nuse sqlx_core::database::Database;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::transaction::TransactionManager;\nuse std::pin::pin;\nuse std::sync::Arc;\n\nsqlx_core::declare_driver_with_optional_migrate!(DRIVER = Sqlite);\n\nimpl AnyConnectionBackend for SqliteConnection {\n    fn name(&self) -> &str {\n        <Sqlite as Database>::NAME\n    }\n\n    fn close(self: Box<Self>) -> BoxFuture<'static, sqlx_core::Result<()>> {\n        Connection::close(*self).boxed()\n    }\n\n    fn close_hard(self: Box<Self>) -> BoxFuture<'static, sqlx_core::Result<()>> {\n        Connection::close_hard(*self).boxed()\n    }\n\n    fn ping(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        Connection::ping(self).boxed()\n    }\n\n    fn begin(&mut self, statement: Option<SqlStr>) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        SqliteTransactionManager::begin(self, statement).boxed()\n    }\n\n    fn commit(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        SqliteTransactionManager::commit(self).boxed()\n    }\n\n    fn rollback(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        SqliteTransactionManager::rollback(self).boxed()\n    }\n\n    fn start_rollback(&mut self) {\n        SqliteTransactionManager::start_rollback(self)\n    }\n\n    fn get_transaction_depth(&self) -> usize {\n        SqliteTransactionManager::get_transaction_depth(self)\n    }\n\n    fn shrink_buffers(&mut self) {\n        // NO-OP.\n    }\n\n    fn flush(&mut self) -> BoxFuture<'_, sqlx_core::Result<()>> {\n        Connection::flush(self).boxed()\n    }\n\n    fn should_flush(&self) -> bool {\n        Connection::should_flush(self)\n    }\n\n    #[cfg(feature = \"migrate\")]\n    fn as_migrate(\n        &mut self,\n    ) -> sqlx_core::Result<&mut (dyn sqlx_core::migrate::Migrate + Send + 'static)> {\n        Ok(self)\n    }\n\n    fn fetch_many(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxStream<'_, sqlx_core::Result<Either<AnyQueryResult, AnyRow>>> {\n        let persistent = persistent && arguments.is_some();\n        let args = arguments.map(map_arguments);\n\n        Box::pin(\n            self.worker\n                .execute(query, args, self.row_channel_size, persistent, None)\n                .map_ok(flume::Receiver::into_stream)\n                .try_flatten_stream()\n                .map(\n                    move |res: sqlx_core::Result<Either<SqliteQueryResult, SqliteRow>>| match res? {\n                        Either::Left(result) => Ok(Either::Left(map_result(result))),\n                        Either::Right(row) => Ok(Either::Right(AnyRow::try_from(&row)?)),\n                    },\n                ),\n        )\n    }\n\n    fn fetch_optional(\n        &mut self,\n        query: SqlStr,\n        persistent: bool,\n        arguments: Option<AnyArguments>,\n    ) -> BoxFuture<'_, sqlx_core::Result<Option<AnyRow>>> {\n        let persistent = persistent && arguments.is_some();\n        let args = arguments.map(map_arguments);\n\n        Box::pin(async move {\n            let mut stream = pin!(\n                self.worker\n                    .execute(query, args, self.row_channel_size, persistent, Some(1))\n                    .map_ok(flume::Receiver::into_stream)\n                    .await?\n            );\n\n            if let Some(Either::Right(row)) = stream.try_next().await? {\n                return Ok(Some(AnyRow::try_from(&row)?));\n            }\n\n            Ok(None)\n        })\n    }\n\n    fn prepare_with<'c, 'q: 'c>(\n        &'c mut self,\n        sql: SqlStr,\n        _parameters: &[AnyTypeInfo],\n    ) -> BoxFuture<'c, sqlx_core::Result<AnyStatement>> {\n        Box::pin(async move {\n            let statement = Executor::prepare_with(self, sql, &[]).await?;\n            let column_names = statement.column_names.clone();\n            AnyStatement::try_from_statement(statement, column_names)\n        })\n    }\n\n    #[cfg(feature = \"offline\")]\n    fn describe(\n        &mut self,\n        sql: SqlStr,\n    ) -> BoxFuture<'_, sqlx_core::Result<sqlx_core::describe::Describe<sqlx_core::any::Any>>> {\n        Box::pin(async move { Executor::describe(self, sql).await?.try_into_any() })\n    }\n}\n\nimpl<'a> TryFrom<&'a SqliteTypeInfo> for AnyTypeInfo {\n    type Error = sqlx_core::Error;\n\n    fn try_from(sqlite_type: &'a SqliteTypeInfo) -> Result<Self, Self::Error> {\n        Ok(AnyTypeInfo {\n            kind: match &sqlite_type.0 {\n                DataType::Null => AnyTypeInfoKind::Null,\n                DataType::Int4 => AnyTypeInfoKind::Integer,\n                DataType::Integer => AnyTypeInfoKind::BigInt,\n                DataType::Float => AnyTypeInfoKind::Double,\n                DataType::Blob => AnyTypeInfoKind::Blob,\n                DataType::Text => AnyTypeInfoKind::Text,\n                _ => {\n                    return Err(sqlx_core::Error::AnyDriverError(\n                        format!(\"Any driver does not support the SQLite type {sqlite_type:?}\")\n                            .into(),\n                    ))\n                }\n            },\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a SqliteColumn> for AnyColumn {\n    type Error = sqlx_core::Error;\n\n    fn try_from(col: &'a SqliteColumn) -> Result<Self, Self::Error> {\n        let type_info =\n            AnyTypeInfo::try_from(&col.type_info).map_err(|e| sqlx_core::Error::ColumnDecode {\n                index: col.name.to_string(),\n                source: e.into(),\n            })?;\n\n        Ok(AnyColumn {\n            ordinal: col.ordinal,\n            name: col.name.clone(),\n            type_info,\n        })\n    }\n}\n\nimpl<'a> TryFrom<&'a SqliteRow> for AnyRow {\n    type Error = sqlx_core::Error;\n\n    fn try_from(row: &'a SqliteRow) -> Result<Self, Self::Error> {\n        AnyRow::map_from(row, row.column_names.clone())\n    }\n}\n\nimpl<'a> TryFrom<&'a AnyConnectOptions> for SqliteConnectOptions {\n    type Error = sqlx_core::Error;\n\n    fn try_from(opts: &'a AnyConnectOptions) -> Result<Self, Self::Error> {\n        let mut opts_out = SqliteConnectOptions::from_url(&opts.database_url)?;\n        opts_out.log_settings = opts.log_settings.clone();\n\n        Ok(opts_out)\n    }\n}\n\n// Infallible alternative to AnyArguments::convert_into()\nfn map_arguments(args: AnyArguments) -> SqliteArguments {\n    let values = args\n        .values\n        .0\n        .into_iter()\n        .map(|val| match val {\n            AnyValueKind::Null(_) => SqliteArgumentValue::Null,\n            AnyValueKind::Bool(b) => SqliteArgumentValue::Int(b as i32),\n            AnyValueKind::SmallInt(i) => SqliteArgumentValue::Int(i as i32),\n            AnyValueKind::Integer(i) => SqliteArgumentValue::Int(i),\n            AnyValueKind::BigInt(i) => SqliteArgumentValue::Int64(i),\n            AnyValueKind::Real(r) => SqliteArgumentValue::Double(r as f64),\n            AnyValueKind::Double(d) => SqliteArgumentValue::Double(d),\n            AnyValueKind::Text(t) => SqliteArgumentValue::Text(Arc::new(t.to_string())),\n            AnyValueKind::Blob(b) => SqliteArgumentValue::Blob(Arc::new(b.to_vec())),\n            // AnyValueKind is `#[non_exhaustive]` but we should have covered everything\n            _ => unreachable!(\"BUG: missing mapping for {val:?}\"),\n        })\n        .collect();\n\n    SqliteArguments {\n        values: SqliteArgumentsBuffer::new(values),\n    }\n}\n\nfn map_result(res: SqliteQueryResult) -> AnyQueryResult {\n    AnyQueryResult {\n        rows_affected: res.rows_affected(),\n        last_insert_id: None,\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/arguments.rs",
    "content": "use crate::encode::{Encode, IsNull};\nuse crate::error::Error;\nuse crate::statement::StatementHandle;\nuse crate::Sqlite;\nuse atoi::atoi;\nuse libsqlite3_sys::SQLITE_OK;\nuse std::sync::Arc;\n\npub(crate) use sqlx_core::arguments::*;\nuse sqlx_core::error::BoxDynError;\n\n#[derive(Debug, Clone)]\npub enum SqliteArgumentValue {\n    Null,\n    Text(Arc<String>),\n    TextSlice(Arc<str>),\n    Blob(Arc<Vec<u8>>),\n    Double(f64),\n    Int(i32),\n    Int64(i64),\n}\n\n#[derive(Default, Debug, Clone)]\npub struct SqliteArguments {\n    pub(crate) values: SqliteArgumentsBuffer,\n}\n\n#[derive(Default, Debug, Clone)]\npub struct SqliteArgumentsBuffer(Vec<SqliteArgumentValue>);\n\nimpl SqliteArguments {\n    pub(crate) fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'t, Sqlite>,\n    {\n        let value_length_before_encoding = self.values.0.len();\n\n        match value.encode(&mut self.values) {\n            Ok(IsNull::Yes) => self.values.0.push(SqliteArgumentValue::Null),\n            Ok(IsNull::No) => {}\n            Err(error) => {\n                // reset the value buffer to its previous value if encoding failed so we don't leave a half-encoded value behind\n                self.values.0.truncate(value_length_before_encoding);\n                return Err(error);\n            }\n        };\n\n        Ok(())\n    }\n}\n\nimpl Arguments for SqliteArguments {\n    type Database = Sqlite;\n\n    fn reserve(&mut self, len: usize, _size_hint: usize) {\n        self.values.0.reserve(len);\n    }\n\n    fn add<'t, T>(&mut self, value: T) -> Result<(), BoxDynError>\n    where\n        T: Encode<'t, Self::Database>,\n    {\n        self.add(value)\n    }\n\n    fn len(&self) -> usize {\n        self.values.0.len()\n    }\n}\n\nimpl SqliteArguments {\n    pub(super) fn bind(&self, handle: &mut StatementHandle, offset: usize) -> Result<usize, Error> {\n        let mut arg_i = offset;\n        // for handle in &statement.handles {\n\n        let cnt = handle.bind_parameter_count();\n\n        for param_i in 1..=cnt {\n            // figure out the index of this bind parameter into our argument tuple\n            let n: usize = if let Some(name) = handle.bind_parameter_name(param_i) {\n                if let Some(name) = name.strip_prefix('?') {\n                    // parameter should have the form ?NNN\n                    atoi(name.as_bytes()).expect(\"parameter of the form ?NNN\")\n                } else if let Some(name) = name.strip_prefix('$') {\n                    // parameter should have the form $NNN\n                    atoi(name.as_bytes()).ok_or_else(|| {\n                        err_protocol!(\n                            \"parameters with non-integer names are not currently supported: {}\",\n                            name\n                        )\n                    })?\n                } else {\n                    return Err(err_protocol!(\"unsupported SQL parameter format: {}\", name));\n                }\n            } else {\n                arg_i += 1;\n                arg_i\n            };\n\n            if n > self.values.0.len() {\n                // SQLite treats unbound variables as NULL\n                // we reproduce this here\n                // If you are reading this and think this should be an error, open an issue and we can\n                // discuss configuring this somehow\n                // Note that the query macros have a different way of enforcing\n                // argument arity\n                break;\n            }\n\n            self.values.0[n - 1].bind(handle, param_i)?;\n        }\n\n        Ok(arg_i - offset)\n    }\n}\n\nimpl SqliteArgumentsBuffer {\n    #[allow(dead_code)] // clippy incorrectly reports this as unused\n    pub(crate) fn new(values: Vec<SqliteArgumentValue>) -> SqliteArgumentsBuffer {\n        Self(values)\n    }\n\n    pub(crate) fn push(&mut self, value: SqliteArgumentValue) {\n        self.0.push(value);\n    }\n}\n\nimpl SqliteArgumentValue {\n    fn bind(&self, handle: &mut StatementHandle, i: usize) -> Result<(), Error> {\n        use SqliteArgumentValue::*;\n\n        let status = match self {\n            Text(v) => handle.bind_text(i, v),\n            TextSlice(v) => handle.bind_text(i, v),\n            Blob(v) => handle.bind_blob(i, v),\n            Int(v) => handle.bind_int(i, *v),\n            Int64(v) => handle.bind_int64(i, *v),\n            Double(v) => handle.bind_double(i, *v),\n            Null => handle.bind_null(i),\n        };\n\n        if status != SQLITE_OK {\n            return Err(handle.last_error().into());\n        }\n\n        Ok(())\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/column.rs",
    "content": "use crate::ext::ustr::UStr;\nuse crate::{Sqlite, SqliteTypeInfo};\n\npub(crate) use sqlx_core::column::*;\n\n#[derive(Debug, Clone)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct SqliteColumn {\n    pub(crate) name: UStr,\n    pub(crate) ordinal: usize,\n    pub(crate) type_info: SqliteTypeInfo,\n\n    #[cfg_attr(feature = \"offline\", serde(default))]\n    pub(crate) origin: ColumnOrigin,\n}\n\nimpl Column for SqliteColumn {\n    type Database = Sqlite;\n\n    fn ordinal(&self) -> usize {\n        self.ordinal\n    }\n\n    fn name(&self) -> &str {\n        &self.name\n    }\n\n    fn type_info(&self) -> &SqliteTypeInfo {\n        &self.type_info\n    }\n\n    fn origin(&self) -> ColumnOrigin {\n        self.origin.clone()\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/collation.rs",
    "content": "use std::cmp::Ordering;\nuse std::ffi::CString;\nuse std::fmt::{self, Debug, Formatter};\nuse std::os::raw::{c_int, c_void};\nuse std::slice;\nuse std::str::from_utf8_unchecked;\nuse std::sync::Arc;\n\nuse libsqlite3_sys::{sqlite3_create_collation_v2, SQLITE_OK, SQLITE_UTF8};\n\nuse crate::connection::handle::ConnectionHandle;\nuse crate::error::Error;\n\n#[derive(Clone)]\npub struct Collation {\n    name: Arc<str>,\n    #[allow(clippy::type_complexity)]\n    collate: Arc<dyn Fn(&str, &str) -> Ordering + Send + Sync + 'static>,\n    // SAFETY: these must match the concrete type of `collate`\n    call: unsafe extern \"C\" fn(\n        arg1: *mut c_void,\n        arg2: c_int,\n        arg3: *const c_void,\n        arg4: c_int,\n        arg5: *const c_void,\n    ) -> c_int,\n    free: unsafe extern \"C\" fn(*mut c_void),\n}\n\nimpl Collation {\n    pub fn new<N, F>(name: N, collate: F) -> Self\n    where\n        N: Into<Arc<str>>,\n        F: Fn(&str, &str) -> Ordering + Send + Sync + 'static,\n    {\n        unsafe extern \"C\" fn drop_arc_value<T>(p: *mut c_void) {\n            drop(Arc::from_raw(p as *mut T));\n        }\n\n        Collation {\n            name: name.into(),\n            collate: Arc::new(collate),\n            call: call_boxed_closure::<F>,\n            free: drop_arc_value::<F>,\n        }\n    }\n\n    pub(crate) fn create(&self, handle: &mut ConnectionHandle) -> Result<(), Error> {\n        let raw_f = Arc::into_raw(Arc::clone(&self.collate));\n        let c_name = CString::new(&*self.name)\n            .map_err(|_| err_protocol!(\"invalid collation name: {:?}\", self.name))?;\n        let flags = SQLITE_UTF8;\n        let r = unsafe {\n            sqlite3_create_collation_v2(\n                handle.as_ptr(),\n                c_name.as_ptr(),\n                flags,\n                raw_f as *mut c_void,\n                Some(self.call),\n                Some(self.free),\n            )\n        };\n\n        if r == SQLITE_OK {\n            Ok(())\n        } else {\n            // The xDestroy callback is not called if the sqlite3_create_collation_v2() function fails.\n            drop(unsafe { Arc::from_raw(raw_f) });\n            Err(handle.expect_error().into())\n        }\n    }\n}\n\nimpl Debug for Collation {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"Collation\")\n            .field(\"name\", &self.name)\n            .finish_non_exhaustive()\n    }\n}\n\npub(crate) fn create_collation<F>(\n    handle: &mut ConnectionHandle,\n    name: &str,\n    compare: F,\n) -> Result<(), Error>\nwhere\n    F: Fn(&str, &str) -> Ordering + Send + Sync + 'static,\n{\n    unsafe extern \"C\" fn free_boxed_value<T>(p: *mut c_void) {\n        drop(Box::from_raw(p as *mut T));\n    }\n\n    let boxed_f: *mut F = Box::into_raw(Box::new(compare));\n    let c_name =\n        CString::new(name).map_err(|_| err_protocol!(\"invalid collation name: {}\", name))?;\n    let flags = SQLITE_UTF8;\n    let r = unsafe {\n        sqlite3_create_collation_v2(\n            handle.as_ptr(),\n            c_name.as_ptr(),\n            flags,\n            boxed_f as *mut c_void,\n            Some(call_boxed_closure::<F>),\n            Some(free_boxed_value::<F>),\n        )\n    };\n\n    if r == SQLITE_OK {\n        Ok(())\n    } else {\n        // The xDestroy callback is not called if the sqlite3_create_collation_v2() function fails.\n        drop(unsafe { Box::from_raw(boxed_f) });\n        Err(handle.expect_error().into())\n    }\n}\n\nunsafe extern \"C\" fn call_boxed_closure<C>(\n    data: *mut c_void,\n    left_len: c_int,\n    left_ptr: *const c_void,\n    right_len: c_int,\n    right_ptr: *const c_void,\n) -> c_int\nwhere\n    C: Fn(&str, &str) -> Ordering,\n{\n    let boxed_f: *mut C = data as *mut C;\n\n    // Note: unwinding is now caught at the FFI boundary:\n    // https://doc.rust-lang.org/nomicon/ffi.html#ffi-and-unwinding\n    assert!(!boxed_f.is_null());\n\n    let left_len =\n        usize::try_from(left_len).unwrap_or_else(|_| panic!(\"left_len out of range: {left_len}\"));\n\n    let right_len = usize::try_from(right_len)\n        .unwrap_or_else(|_| panic!(\"right_len out of range: {right_len}\"));\n\n    let s1 = {\n        let c_slice = slice::from_raw_parts(left_ptr as *const u8, left_len);\n        from_utf8_unchecked(c_slice)\n    };\n    let s2 = {\n        let c_slice = slice::from_raw_parts(right_ptr as *const u8, right_len);\n        from_utf8_unchecked(c_slice)\n    };\n    let t = (*boxed_f)(s1, s2);\n\n    match t {\n        Ordering::Less => -1,\n        Ordering::Equal => 0,\n        Ordering::Greater => 1,\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/describe.rs",
    "content": "use crate::connection::explain::explain;\nuse crate::connection::ConnectionState;\nuse crate::describe::Describe;\nuse crate::error::Error;\nuse crate::statement::VirtualStatement;\nuse crate::type_info::DataType;\nuse crate::{Sqlite, SqliteColumn};\nuse sqlx_core::sql_str::SqlStr;\nuse sqlx_core::Either;\nuse std::convert::identity;\n\npub(crate) fn describe(\n    conn: &mut ConnectionState,\n    query: SqlStr,\n) -> Result<Describe<Sqlite>, Error> {\n    // describing a statement from SQLite can be involved\n    // each SQLx statement is comprised of multiple SQL statements\n\n    let mut statement = VirtualStatement::new(query.as_str(), false)?;\n\n    let mut columns = Vec::new();\n    let mut nullable = Vec::new();\n    let mut num_params = 0;\n\n    // we start by finding the first statement that *can* return results\n    while let Some(stmt) = statement.prepare_next(&mut conn.handle)? {\n        num_params += stmt.handle.bind_parameter_count();\n\n        let mut stepped = false;\n\n        let num = stmt.handle.column_count();\n        if num == 0 {\n            // no columns in this statement; skip\n            continue;\n        }\n\n        // next we try to use [column_decltype] to inspect the type of each column\n        columns.reserve(num);\n\n        // as a last resort, we explain the original query and attempt to\n        // infer what would the expression types be as a fallback\n        // to [column_decltype]\n\n        // if explain.. fails, ignore the failure and we'll have no fallback\n        let (fallback, fallback_nullable) = match explain(conn, stmt.handle.sql()) {\n            Ok(v) => v,\n            Err(error) => {\n                tracing::debug!(%error, \"describe: explain introspection failed\");\n\n                (vec![], vec![])\n            }\n        };\n\n        for col in 0..num {\n            let name = stmt.handle.column_name(col).to_owned();\n\n            let origin = stmt.handle.column_origin(col);\n\n            let type_info = if let Some(ty) = stmt.handle.column_decltype(col) {\n                ty\n            } else {\n                // if that fails, we back up and attempt to step the statement\n                // once *if* its read-only and then use [column_type] as a\n                // fallback to [column_decltype]\n                if !stepped && stmt.handle.read_only() {\n                    stepped = true;\n                    let _ = stmt.handle.step();\n                }\n\n                let mut ty = stmt.handle.column_type_info(col);\n\n                if ty.0 == DataType::Null {\n                    if let Some(fallback) = fallback.get(col).cloned() {\n                        ty = fallback;\n                    }\n                }\n\n                ty\n            };\n\n            // check explain\n            let col_nullable = stmt.handle.column_nullable(col)?;\n            let exp_nullable = fallback_nullable.get(col).copied().and_then(identity);\n\n            nullable.push(exp_nullable.or(col_nullable));\n\n            columns.push(SqliteColumn {\n                name: name.into(),\n                type_info,\n                ordinal: col,\n                origin,\n            });\n        }\n    }\n\n    Ok(Describe {\n        columns,\n        parameters: Some(Either::Right(num_params)),\n        nullable,\n    })\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/deserialize.rs",
    "content": "use super::ConnectionState;\nuse crate::{error::Error, SqliteConnection, SqliteError};\nuse libsqlite3_sys::{\n    sqlite3_deserialize, sqlite3_free, sqlite3_malloc64, sqlite3_serialize,\n    SQLITE_DESERIALIZE_FREEONCLOSE, SQLITE_DESERIALIZE_READONLY, SQLITE_DESERIALIZE_RESIZEABLE,\n    SQLITE_NOMEM, SQLITE_OK,\n};\nuse std::ffi::c_char;\nuse std::fmt::Debug;\nuse std::{\n    ops::{Deref, DerefMut},\n    ptr,\n    ptr::NonNull,\n};\n\nimpl SqliteConnection {\n    /// Serialize the given SQLite database schema using [`sqlite3_serialize()`].\n    ///\n    /// The returned buffer is a SQLite managed allocation containing the equivalent data\n    /// as writing the database to disk. It is freed on-drop.\n    ///  \n    /// To serialize the primary, unqualified schema (`main`), pass `None` for the schema name.\n    ///\n    /// # Errors\n    /// * [`Error::InvalidArgument`] if the schema name contains a zero/NUL byte (`\\0`).\n    /// * [`Error::Database`] if the schema does not exist or another error occurs.\n    ///\n    /// [`sqlite3_serialize()`]: https://sqlite.org/c3ref/serialize.html\n    #[cfg_attr(docsrs, doc(cfg(feature = \"sqlite-deserialize\")))]\n    pub async fn serialize(&mut self, schema: Option<&str>) -> Result<SqliteOwnedBuf, Error> {\n        let schema = schema.map(SchemaName::try_from).transpose()?;\n\n        self.worker.serialize(schema).await\n    }\n\n    /// Deserialize a SQLite database from a buffer into the specified schema using [`sqlite3_deserialize()`].\n    ///\n    /// The given schema will be disconnected and re-connected as an in-memory database\n    /// backed by `data`, which should be the serialized form of a database previously returned\n    /// by a call to [`Self::serialize()`], documented as being equivalent to\n    /// the contents of the database file on disk.\n    ///\n    /// An error will be returned if a schema with the given name is not already attached.  \n    /// You can use `ATTACH ':memory' as \"<schema name>\"` to create an empty schema first.\n    ///\n    /// Pass `None` to deserialize to the primary, unqualified schema (`main`).\n    ///\n    /// The SQLite connection will take ownership of `data` and will free it when the connection\n    /// is closed or the schema is detached ([`SQLITE_DESERIALIZE_FREEONCLOSE`][deserialize-flags]).\n    ///\n    /// If `read_only` is `true`, the schema is opened as read-only ([`SQLITE_DESERIALIZE_READONLY`][deserialize-flags]).  \n    /// If `false`, the schema is marked as resizable ([`SQLITE_DESERIALIZE_RESIZABLE`][deserialize-flags]).\n    ///\n    /// If the database is in WAL mode, an error is returned.\n    /// See [`sqlite3_deserialize()`] for details.\n    ///\n    /// # Errors\n    /// * [`Error::InvalidArgument`] if the schema name contains a zero/NUL byte (`\\0`).\n    /// * [`Error::Database`] if an error occurs during deserialization.\n    ///\n    /// [`sqlite3_deserialize()`]: https://sqlite.org/c3ref/deserialize.html\n    /// [deserialize-flags]: https://sqlite.org/c3ref/c_deserialize_freeonclose.html\n    #[cfg_attr(docsrs, doc(cfg(feature = \"sqlite-deserialize\")))]\n    pub async fn deserialize(\n        &mut self,\n        schema: Option<&str>,\n        data: SqliteOwnedBuf,\n        read_only: bool,\n    ) -> Result<(), Error> {\n        let schema = schema.map(SchemaName::try_from).transpose()?;\n\n        self.worker.deserialize(schema, data, read_only).await\n    }\n}\n\npub(crate) fn serialize(\n    conn: &mut ConnectionState,\n    schema: Option<SchemaName>,\n) -> Result<SqliteOwnedBuf, Error> {\n    let mut size = 0;\n\n    let buf = unsafe {\n        let ptr = sqlite3_serialize(\n            conn.handle.as_ptr(),\n            schema.as_ref().map_or(ptr::null(), SchemaName::as_ptr),\n            &mut size,\n            0,\n        );\n\n        // looking at the source, `sqlite3_serialize` actually sets `size = -1` on error:\n        // https://github.com/sqlite/sqlite/blob/da5f81387843f92652128087a8f8ecef0b79461d/src/memdb.c#L776\n        usize::try_from(size)\n            .ok()\n            .and_then(|size| SqliteOwnedBuf::from_raw(ptr, size))\n    };\n\n    if let Some(buf) = buf {\n        return Ok(buf);\n    }\n\n    if let Some(error) = conn.handle.last_error() {\n        return Err(error.into());\n    }\n\n    if size > 0 {\n        // If `size` is positive but `sqlite3_serialize` still returned NULL,\n        // the most likely culprit is an out-of-memory condition.\n        return Err(SqliteError::from_code(SQLITE_NOMEM).into());\n    }\n\n    // Otherwise, the schema was probably not found.\n    // We return the equivalent error as when you try to execute `PRAGMA <schema>.page_count`\n    // against a non-existent schema.\n    Err(SqliteError::generic(format!(\n        \"database {} does not exist\",\n        schema.as_ref().map_or(\"main\", SchemaName::as_str)\n    ))\n    .into())\n}\n\npub(crate) fn deserialize(\n    conn: &mut ConnectionState,\n    schema: Option<SchemaName>,\n    data: SqliteOwnedBuf,\n    read_only: bool,\n) -> Result<(), Error> {\n    // SQLITE_DESERIALIZE_FREEONCLOSE causes SQLite to take ownership of the buffer\n    let mut flags = SQLITE_DESERIALIZE_FREEONCLOSE;\n    if read_only {\n        flags |= SQLITE_DESERIALIZE_READONLY;\n    } else {\n        flags |= SQLITE_DESERIALIZE_RESIZEABLE;\n    }\n\n    let (buf, size) = data.into_raw();\n\n    let rc = unsafe {\n        sqlite3_deserialize(\n            conn.handle.as_ptr(),\n            schema.as_ref().map_or(ptr::null(), SchemaName::as_ptr),\n            buf,\n            i64::try_from(size).unwrap(),\n            i64::try_from(size).unwrap(),\n            flags,\n        )\n    };\n\n    match rc {\n        SQLITE_OK => Ok(()),\n        SQLITE_NOMEM => Err(SqliteError::from_code(SQLITE_NOMEM).into()),\n        // SQLite unfortunately doesn't set any specific message for deserialization errors.\n        _ => Err(SqliteError::generic(\"an error occurred during deserialization\").into()),\n    }\n}\n\n/// Memory buffer owned and allocated by SQLite. Freed on drop.\n///\n/// Intended primarily for use with [`SqliteConnection::serialize()`] and [`SqliteConnection::deserialize()`].\n///\n/// Can be created from `&[u8]` using the `TryFrom` impl. The slice must not be empty.\n#[derive(Debug)]\npub struct SqliteOwnedBuf {\n    ptr: NonNull<u8>,\n    size: usize,\n}\n\nunsafe impl Send for SqliteOwnedBuf {}\nunsafe impl Sync for SqliteOwnedBuf {}\n\nimpl Drop for SqliteOwnedBuf {\n    fn drop(&mut self) {\n        unsafe {\n            sqlite3_free(self.ptr.as_ptr().cast());\n        }\n    }\n}\n\nimpl SqliteOwnedBuf {\n    /// Uses `sqlite3_malloc` to allocate a buffer and returns a pointer to it.\n    ///\n    /// # Safety\n    /// The allocated buffer is uninitialized.\n    unsafe fn with_capacity(size: usize) -> Option<SqliteOwnedBuf> {\n        let ptr = sqlite3_malloc64(u64::try_from(size).unwrap()).cast::<u8>();\n        Self::from_raw(ptr, size)\n    }\n\n    /// Creates a new mem buffer from a pointer that has been created with sqlite_malloc\n    ///\n    /// # Safety:\n    /// * The pointer must point to a valid allocation created by `sqlite3_malloc()`, or `NULL`.\n    unsafe fn from_raw(ptr: *mut u8, size: usize) -> Option<Self> {\n        Some(Self {\n            ptr: NonNull::new(ptr)?,\n            size,\n        })\n    }\n\n    fn into_raw(self) -> (*mut u8, usize) {\n        let raw = (self.ptr.as_ptr(), self.size);\n        // this is used in sqlite_deserialize and\n        // underlying buffer must not be freed\n        std::mem::forget(self);\n        raw\n    }\n}\n\n/// # Errors\n/// Returns [`Error::InvalidArgument`] if the slice is empty.\nimpl TryFrom<&[u8]> for SqliteOwnedBuf {\n    type Error = Error;\n\n    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {\n        unsafe {\n            // SAFETY: `buf` is not initialized until `ptr::copy_nonoverlapping` completes.\n            let mut buf = Self::with_capacity(bytes.len()).ok_or_else(|| {\n                Error::InvalidArgument(\"SQLite owned buffer cannot be empty\".to_string())\n            })?;\n            ptr::copy_nonoverlapping(bytes.as_ptr(), buf.ptr.as_mut(), buf.size);\n            Ok(buf)\n        }\n    }\n}\n\nimpl Deref for SqliteOwnedBuf {\n    type Target = [u8];\n\n    fn deref(&self) -> &Self::Target {\n        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.size) }\n    }\n}\n\nimpl DerefMut for SqliteOwnedBuf {\n    fn deref_mut(&mut self) -> &mut Self::Target {\n        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_mut(), self.size) }\n    }\n}\n\nimpl AsRef<[u8]> for SqliteOwnedBuf {\n    fn as_ref(&self) -> &[u8] {\n        self.deref()\n    }\n}\n\nimpl AsMut<[u8]> for SqliteOwnedBuf {\n    fn as_mut(&mut self) -> &mut [u8] {\n        self.deref_mut()\n    }\n}\n\n/// Checked schema name to pass to SQLite.\n///\n/// # Safety:\n/// * Valid UTF-8 (not guaranteed by `CString`)\n/// * No internal zero bytes (`\\0`) (not guaranteed by `String`)\n/// * Terminated with a zero byte (`\\0`) (not guaranteed by `String`)\n#[derive(Debug)]\npub(crate) struct SchemaName(Box<str>);\n\nimpl SchemaName {\n    /// Get the schema name as a string without the zero byte terminator.\n    pub fn as_str(&self) -> &str {\n        &self.0[..self.0.len() - 1]\n    }\n\n    /// Get a pointer to the string data, suitable for passing as C's `*const char`.\n    ///\n    /// # Safety\n    /// The string data is guaranteed to be terminated with a zero byte.\n    pub fn as_ptr(&self) -> *const c_char {\n        self.0.as_ptr() as *const c_char\n    }\n}\n\nimpl<'a> TryFrom<&'a str> for SchemaName {\n    type Error = Error;\n\n    fn try_from(name: &'a str) -> Result<Self, Self::Error> {\n        // SAFETY: we must ensure that the string does not contain an internal NULL byte\n        if let Some(pos) = name.as_bytes().iter().position(|&b| b == 0) {\n            return Err(Error::InvalidArgument(format!(\n                \"schema name {name:?} contains a zero byte at index {pos}\"\n            )));\n        }\n\n        let capacity = name.len().checked_add(1).unwrap();\n\n        let mut s = String::new();\n        // `String::with_capacity()` does not guarantee that it will not overallocate,\n        // which might mean an unnecessary reallocation to make `capacity == len`\n        // in the conversion to `Box<str>`.\n        s.reserve_exact(capacity);\n\n        s.push_str(name);\n        s.push('\\0');\n\n        Ok(SchemaName(s.into()))\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/establish.rs",
    "content": "use crate::connection::handle::ConnectionHandle;\nuse crate::connection::LogSettings;\nuse crate::connection::{ConnectionState, Statements};\nuse crate::error::Error;\nuse crate::SqliteConnectOptions;\nuse libsqlite3_sys::{\n    sqlite3_busy_timeout, SQLITE_OPEN_CREATE, SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_MEMORY,\n    SQLITE_OPEN_NOMUTEX, SQLITE_OPEN_PRIVATECACHE, SQLITE_OPEN_READONLY, SQLITE_OPEN_READWRITE,\n    SQLITE_OPEN_SHAREDCACHE, SQLITE_OPEN_URI,\n};\nuse percent_encoding::NON_ALPHANUMERIC;\nuse std::collections::BTreeMap;\nuse std::ffi::CString;\nuse std::io;\nuse std::sync::atomic::{AtomicUsize, Ordering};\nuse std::time::Duration;\n\n#[cfg(feature = \"load-extension\")]\nuse sqlx_core::IndexMap;\n\n// This was originally `AtomicU64` but that's not supported on MIPS (or PowerPC):\n// https://github.com/launchbadge/sqlx/issues/2859\n// https://doc.rust-lang.org/stable/std/sync/atomic/index.html#portability\nstatic THREAD_ID: AtomicUsize = AtomicUsize::new(0);\n\npub struct EstablishParams {\n    filename: CString,\n    open_flags: i32,\n    busy_timeout: Duration,\n    statement_cache_capacity: usize,\n    log_settings: LogSettings,\n    #[cfg(feature = \"load-extension\")]\n    extensions: IndexMap<CString, Option<CString>>,\n    pub(crate) thread_name: String,\n    pub(crate) command_channel_size: usize,\n    #[cfg(feature = \"regexp\")]\n    register_regexp_function: bool,\n}\n\nimpl EstablishParams {\n    pub fn from_options(options: &SqliteConnectOptions) -> Result<Self, Error> {\n        let mut filename = options\n            .filename\n            .to_str()\n            .ok_or_else(|| {\n                io::Error::new(\n                    io::ErrorKind::InvalidData,\n                    \"filename passed to SQLite must be valid UTF-8\",\n                )\n            })?\n            .to_owned();\n\n        // Set common flags we expect to have in sqlite\n        let mut flags = SQLITE_OPEN_URI;\n\n        // By default, we connect to an in-memory database.\n        // [SQLITE_OPEN_NOMUTEX] will instruct [sqlite3_open_v2] to return an error if it\n        // cannot satisfy our wish for a thread-safe, lock-free connection object\n\n        flags |= if options.serialized {\n            SQLITE_OPEN_FULLMUTEX\n        } else {\n            SQLITE_OPEN_NOMUTEX\n        };\n\n        flags |= if options.read_only {\n            SQLITE_OPEN_READONLY\n        } else if options.create_if_missing {\n            SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE\n        } else {\n            SQLITE_OPEN_READWRITE\n        };\n\n        if options.in_memory {\n            flags |= SQLITE_OPEN_MEMORY;\n        }\n\n        flags |= if options.shared_cache {\n            SQLITE_OPEN_SHAREDCACHE\n        } else {\n            SQLITE_OPEN_PRIVATECACHE\n        };\n\n        let mut query_params = BTreeMap::new();\n\n        if options.immutable {\n            query_params.insert(\"immutable\", \"true\");\n        }\n\n        if let Some(vfs) = options.vfs.as_deref() {\n            query_params.insert(\"vfs\", vfs);\n        }\n\n        if !query_params.is_empty() {\n            filename = format!(\n                \"file:{}?\",\n                percent_encoding::percent_encode(filename.as_bytes(), NON_ALPHANUMERIC),\n            );\n\n            // Suffix serializer automatically handles `&` separators for us.\n            let filename_len = filename.len();\n            filename = form_urlencoded::Serializer::for_suffix(filename, filename_len)\n                .extend_pairs(query_params)\n                .finish();\n        }\n\n        let filename = CString::new(filename).map_err(|_| {\n            io::Error::new(\n                io::ErrorKind::InvalidData,\n                \"filename passed to SQLite must not contain nul bytes\",\n            )\n        })?;\n\n        #[cfg(feature = \"load-extension\")]\n        let extensions = options\n            .extensions\n            .iter()\n            .map(|(name, entry)| {\n                let entry = entry\n                    .as_ref()\n                    .map(|e| {\n                        CString::new(e.as_bytes()).map_err(|_| {\n                            io::Error::new(\n                                io::ErrorKind::InvalidData,\n                                \"extension entrypoint names passed to SQLite must not contain nul bytes\"\n                            )\n                        })\n                    })\n                    .transpose()?;\n                Ok((\n                    CString::new(name.as_bytes()).map_err(|_| {\n                        io::Error::new(\n                            io::ErrorKind::InvalidData,\n                            \"extension names passed to SQLite must not contain nul bytes\",\n                        )\n                    })?,\n                    entry,\n                ))\n            })\n            .collect::<Result<IndexMap<CString, Option<CString>>, io::Error>>()?;\n\n        let thread_id = THREAD_ID.fetch_add(1, Ordering::AcqRel);\n\n        Ok(Self {\n            filename,\n            open_flags: flags,\n            busy_timeout: options.busy_timeout,\n            statement_cache_capacity: options.statement_cache_capacity,\n            log_settings: options.log_settings.clone(),\n            #[cfg(feature = \"load-extension\")]\n            extensions,\n            thread_name: (options.thread_name)(thread_id as u64),\n            command_channel_size: options.command_channel_size,\n            #[cfg(feature = \"regexp\")]\n            register_regexp_function: options.register_regexp_function,\n        })\n    }\n\n    pub(crate) fn establish(&self) -> Result<ConnectionState, Error> {\n        let mut handle = ConnectionHandle::open(&self.filename, self.open_flags)?;\n\n        #[cfg(feature = \"load-extension\")]\n        unsafe {\n            self.apply_extensions(&mut handle)?;\n        }\n\n        #[cfg(feature = \"regexp\")]\n        if self.register_regexp_function {\n            // configure a `regexp` function for sqlite, it does not come with one by default\n            let status = crate::regexp::register(handle.as_ptr());\n            if status != libsqlite3_sys::SQLITE_OK {\n                return Err(Error::Database(Box::new(handle.expect_error())));\n            }\n        }\n\n        // Configure a busy timeout\n        // This causes SQLite to automatically sleep in increasing intervals until the time\n        // when there is something locked during [sqlite3_step].\n        //\n        // We also need to convert the u128 value to i32, checking we're not overflowing.\n        let ms = i32::try_from(self.busy_timeout.as_millis())\n            .expect(\"Given busy timeout value is too big.\");\n\n        handle.call_with_result(|db| unsafe { sqlite3_busy_timeout(db, ms) })?;\n\n        Ok(ConnectionState {\n            handle,\n            statements: Statements::new(self.statement_cache_capacity),\n            log_settings: self.log_settings.clone(),\n            progress_handler_callback: None,\n            update_hook_callback: None,\n            #[cfg(feature = \"preupdate-hook\")]\n            preupdate_hook_callback: None,\n            commit_hook_callback: None,\n            rollback_hook_callback: None,\n        })\n    }\n\n    #[cfg(feature = \"load-extension\")]\n    unsafe fn apply_extensions(&self, handle: &mut ConnectionHandle) -> Result<(), Error> {\n        use libsqlite3_sys::{sqlite3_free, sqlite3_load_extension};\n        use std::ffi::{c_int, CStr};\n        use std::ptr;\n\n        /// `true` enables *just* `sqlite3_load_extension`, false disables *all* extension loading.\n        fn enable_load_extension(\n            handle: &mut ConnectionHandle,\n            enabled: bool,\n        ) -> Result<(), Error> {\n            use libsqlite3_sys::{sqlite3_db_config, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION};\n\n            // SAFETY: we have exclusive access and this matches the expected signature\n            // <https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension>\n            handle.call_with_result(|db| unsafe {\n                // https://doc.rust-lang.org/reference/expressions/operator-expr.html#r-expr.as.bool-char-as-int\n                sqlite3_db_config(\n                    db,\n                    SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION,\n                    enabled as c_int,\n                    ptr::null_mut::<c_int>(),\n                )\n            })?;\n\n            Ok(())\n        }\n\n        if self.extensions.is_empty() {\n            return Ok(());\n        }\n\n        // We enable extension loading only so long as *we're* doing it.\n        enable_load_extension(handle, true)?;\n\n        for (name, entrypoint) in &self.extensions {\n            let name_ptr = name.as_ptr();\n            let entrypoint_ptr = entrypoint.as_ref().map_or_else(ptr::null, |s| s.as_ptr());\n            let mut err_msg_ptr = ptr::null_mut();\n\n            // SAFETY:\n            // * we have exclusive access\n            // * all pointers are initialized\n            // * we warn the user about loading extensions in documentation\n            handle\n                .call_with_result(|db| unsafe {\n                    sqlite3_load_extension(db, name_ptr, entrypoint_ptr, &mut err_msg_ptr)\n                })\n                .map_err(|e| {\n                    if !err_msg_ptr.is_null() {\n                        // SAFETY: pointer is not-null,\n                        // and we copy the error message to an allocation we own.\n                        let err_msg = unsafe { CStr::from_ptr(err_msg_ptr) }\n                            // In practice, the string *should* be UTF-8.\n                            .to_string_lossy()\n                            .into_owned();\n\n                        // SAFETY: we're expected to free the error message afterward.\n                        unsafe {\n                            sqlite3_free(err_msg_ptr.cast());\n                        }\n\n                        e.with_message(err_msg)\n                    } else {\n                        e\n                    }\n                })?;\n        }\n\n        // We then disable extension loading immediately afterward.\n        enable_load_extension(handle, false)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/execute.rs",
    "content": "use crate::connection::{ConnectionHandle, ConnectionState};\nuse crate::error::Error;\nuse crate::logger::QueryLogger;\nuse crate::statement::{StatementHandle, VirtualStatement};\nuse crate::{SqliteArguments, SqliteQueryResult, SqliteRow};\nuse sqlx_core::sql_str::SqlSafeStr;\nuse sqlx_core::Either;\n\npub struct ExecuteIter<'a> {\n    handle: &'a mut ConnectionHandle,\n    statement: &'a mut VirtualStatement,\n    logger: QueryLogger,\n    args: Option<SqliteArguments>,\n\n    /// since a `VirtualStatement` can encompass multiple actual statements,\n    /// this keeps track of the number of arguments so far\n    args_used: usize,\n\n    goto_next: bool,\n}\n\npub(crate) fn iter(\n    conn: &mut ConnectionState,\n    query: impl SqlSafeStr,\n    args: Option<SqliteArguments>,\n    persistent: bool,\n) -> Result<ExecuteIter<'_>, Error> {\n    let query = query.into_sql_str();\n    // fetch the cached statement or allocate a new one\n    let statement = conn.statements.get(query.as_str(), persistent)?;\n\n    let logger = QueryLogger::new(query, conn.log_settings.clone());\n\n    Ok(ExecuteIter {\n        handle: &mut conn.handle,\n        statement,\n        logger,\n        args,\n        args_used: 0,\n        goto_next: true,\n    })\n}\n\nfn bind(\n    statement: &mut StatementHandle,\n    arguments: &Option<SqliteArguments>,\n    offset: usize,\n) -> Result<usize, Error> {\n    let mut n = 0;\n\n    if let Some(arguments) = arguments {\n        n = arguments.bind(statement, offset)?;\n    }\n\n    Ok(n)\n}\n\nimpl ExecuteIter<'_> {\n    pub fn finish(self) -> Result<(), Error> {\n        for res in self {\n            let _ = res?;\n        }\n\n        Ok(())\n    }\n}\n\nimpl Iterator for ExecuteIter<'_> {\n    type Item = Result<Either<SqliteQueryResult, SqliteRow>, Error>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        let statement = if self.goto_next {\n            let statement = match self.statement.prepare_next(self.handle) {\n                Ok(Some(statement)) => statement,\n                Ok(None) => return None,\n                Err(e) => return Some(Err(e)),\n            };\n\n            self.goto_next = false;\n\n            // sanity check: ensure the VM is reset and the bindings are cleared\n            if let Err(e) = statement.handle.reset() {\n                return Some(Err(e.into()));\n            }\n\n            statement.handle.clear_bindings();\n\n            match bind(statement.handle, &self.args, self.args_used) {\n                Ok(args_used) => self.args_used += args_used,\n                Err(e) => return Some(Err(e)),\n            }\n\n            statement\n        } else {\n            self.statement.current()?\n        };\n\n        match statement.handle.step() {\n            Ok(true) => {\n                self.logger.increment_rows_returned();\n\n                Some(Ok(Either::Right(SqliteRow::current(\n                    statement.handle,\n                    statement.columns,\n                    statement.column_names,\n                ))))\n            }\n            Ok(false) => {\n                let last_insert_rowid = self.handle.last_insert_rowid();\n\n                let changes = statement.handle.changes();\n                self.logger.increase_rows_affected(changes);\n\n                let done = SqliteQueryResult {\n                    changes,\n                    last_insert_rowid,\n                };\n\n                self.goto_next = true;\n\n                Some(Ok(Either::Left(done)))\n            }\n            Err(e) => Some(Err(e.into())),\n        }\n    }\n}\n\nimpl Drop for ExecuteIter<'_> {\n    fn drop(&mut self) {\n        self.statement.reset().ok();\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/executor.rs",
    "content": "use crate::{\n    Sqlite, SqliteConnection, SqliteQueryResult, SqliteRow, SqliteStatement, SqliteTypeInfo,\n};\nuse futures_core::future::BoxFuture;\nuse futures_core::stream::BoxStream;\nuse futures_util::{stream, FutureExt, StreamExt, TryFutureExt, TryStreamExt};\nuse sqlx_core::error::Error;\nuse sqlx_core::executor::{Execute, Executor};\nuse sqlx_core::sql_str::SqlStr;\nuse sqlx_core::Either;\nuse std::{future, pin::pin};\n\nimpl<'c> Executor<'c> for &'c mut SqliteConnection {\n    type Database = Sqlite;\n\n    fn fetch_many<'e, 'q, E>(\n        self,\n        mut query: E,\n    ) -> BoxStream<'e, Result<Either<SqliteQueryResult, SqliteRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        let arguments = match query.take_arguments().map_err(Error::Encode) {\n            Ok(arguments) => arguments,\n            Err(error) => return stream::once(future::ready(Err(error))).boxed(),\n        };\n        let persistent = query.persistent() && arguments.is_some();\n        let sql = query.sql();\n\n        Box::pin(\n            self.worker\n                .execute(sql, arguments, self.row_channel_size, persistent, None)\n                .map_ok(flume::Receiver::into_stream)\n                .try_flatten_stream(),\n        )\n    }\n\n    fn fetch_optional<'e, 'q, E>(\n        self,\n        mut query: E,\n    ) -> BoxFuture<'e, Result<Option<SqliteRow>, Error>>\n    where\n        'c: 'e,\n        E: Execute<'q, Self::Database>,\n        'q: 'e,\n        E: 'q,\n    {\n        let arguments = match query.take_arguments().map_err(Error::Encode) {\n            Ok(arguments) => arguments,\n            Err(error) => return future::ready(Err(error)).boxed(),\n        };\n        let persistent = query.persistent() && arguments.is_some();\n\n        Box::pin(async move {\n            let sql = query.sql();\n            let mut stream = pin!(self\n                .worker\n                .execute(sql, arguments, self.row_channel_size, persistent, Some(1))\n                .map_ok(flume::Receiver::into_stream)\n                .try_flatten_stream());\n\n            while let Some(res) = stream.try_next().await? {\n                if let Either::Right(row) = res {\n                    return Ok(Some(row));\n                }\n            }\n\n            Ok(None)\n        })\n    }\n\n    fn prepare_with<'e>(\n        self,\n        sql: SqlStr,\n        _parameters: &[SqliteTypeInfo],\n    ) -> BoxFuture<'e, Result<SqliteStatement, Error>>\n    where\n        'c: 'e,\n    {\n        Box::pin(async move {\n            let statement = self.worker.prepare(sql).await?;\n\n            Ok(statement)\n        })\n    }\n\n    #[doc(hidden)]\n    #[cfg(feature = \"offline\")]\n    fn describe<'e>(\n        self,\n        sql: SqlStr,\n    ) -> BoxFuture<'e, Result<sqlx_core::describe::Describe<Sqlite>, Error>>\n    where\n        'c: 'e,\n    {\n        Box::pin(async move { self.worker.describe(sql).await })\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/explain.rs",
    "content": "// Bad casts in this module SHOULD NOT result in a SQL injection\n// https://github.com/launchbadge/sqlx/issues/3440\n#![allow(\n    clippy::cast_possible_truncation,\n    clippy::cast_possible_wrap,\n    clippy::cast_sign_loss\n)]\nuse crate::connection::intmap::IntMap;\nuse crate::connection::{execute, ConnectionState};\nuse crate::error::Error;\nuse crate::from_row::FromRow;\nuse crate::logger::{BranchParent, BranchResult, DebugDiff};\nuse crate::type_info::DataType;\nuse crate::SqliteTypeInfo;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse sqlx_core::{hash_map, HashMap};\nuse std::fmt::Debug;\nuse std::str::from_utf8;\n\n// affinity\nconst SQLITE_AFF_NONE: u8 = 0x40; /* '@' */\nconst SQLITE_AFF_BLOB: u8 = 0x41; /* 'A' */\nconst SQLITE_AFF_TEXT: u8 = 0x42; /* 'B' */\nconst SQLITE_AFF_NUMERIC: u8 = 0x43; /* 'C' */\nconst SQLITE_AFF_INTEGER: u8 = 0x44; /* 'D' */\nconst SQLITE_AFF_REAL: u8 = 0x45; /* 'E' */\n\n// opcodes\nconst OP_INIT: &str = \"Init\";\nconst OP_GOTO: &str = \"Goto\";\nconst OP_DECR_JUMP_ZERO: &str = \"DecrJumpZero\";\nconst OP_DELETE: &str = \"Delete\";\nconst OP_ELSE_EQ: &str = \"ElseEq\";\nconst OP_EQ: &str = \"Eq\";\nconst OP_END_COROUTINE: &str = \"EndCoroutine\";\nconst OP_FILTER: &str = \"Filter\";\nconst OP_FK_IF_ZERO: &str = \"FkIfZero\";\nconst OP_FOUND: &str = \"Found\";\nconst OP_GE: &str = \"Ge\";\nconst OP_GO_SUB: &str = \"Gosub\";\nconst OP_GT: &str = \"Gt\";\nconst OP_IDX_GE: &str = \"IdxGE\";\nconst OP_IDX_GT: &str = \"IdxGT\";\nconst OP_IDX_LE: &str = \"IdxLE\";\nconst OP_IDX_LT: &str = \"IdxLT\";\nconst OP_IF: &str = \"If\";\nconst OP_IF_NO_HOPE: &str = \"IfNoHope\";\nconst OP_IF_NOT: &str = \"IfNot\";\nconst OP_IF_NOT_OPEN: &str = \"IfNotOpen\";\nconst OP_IF_NOT_ZERO: &str = \"IfNotZero\";\nconst OP_IF_NULL_ROW: &str = \"IfNullRow\";\nconst OP_IF_POS: &str = \"IfPos\";\nconst OP_IF_SMALLER: &str = \"IfSmaller\";\nconst OP_INCR_VACUUM: &str = \"IncrVacuum\";\nconst OP_INIT_COROUTINE: &str = \"InitCoroutine\";\nconst OP_IS_NULL: &str = \"IsNull\";\nconst OP_IS_NULL_OR_TYPE: &str = \"IsNullOrType\";\nconst OP_LAST: &str = \"Last\";\nconst OP_LE: &str = \"Le\";\nconst OP_LT: &str = \"Lt\";\nconst OP_MUST_BE_INT: &str = \"MustBeInt\";\nconst OP_NE: &str = \"Ne\";\nconst OP_NEXT: &str = \"Next\";\nconst OP_NO_CONFLICT: &str = \"NoConflict\";\nconst OP_NOT_EXISTS: &str = \"NotExists\";\nconst OP_NOT_NULL: &str = \"NotNull\";\nconst OP_ONCE: &str = \"Once\";\nconst OP_PREV: &str = \"Prev\";\nconst OP_PROGRAM: &str = \"Program\";\nconst OP_RETURN: &str = \"Return\";\nconst OP_REWIND: &str = \"Rewind\";\nconst OP_ROW_DATA: &str = \"RowData\";\nconst OP_ROW_SET_READ: &str = \"RowSetRead\";\nconst OP_ROW_SET_TEST: &str = \"RowSetTest\";\nconst OP_SEEK_GE: &str = \"SeekGE\";\nconst OP_SEEK_GT: &str = \"SeekGT\";\nconst OP_SEEK_LE: &str = \"SeekLE\";\nconst OP_SEEK_LT: &str = \"SeekLT\";\nconst OP_SEEK_ROW_ID: &str = \"SeekRowid\";\nconst OP_SEEK_SCAN: &str = \"SeekScan\";\nconst OP_SEQUENCE: &str = \"Sequence\";\nconst OP_SEQUENCE_TEST: &str = \"SequenceTest\";\nconst OP_SORT: &str = \"Sort\";\nconst OP_SORTER_DATA: &str = \"SorterData\";\nconst OP_SORTER_INSERT: &str = \"SorterInsert\";\nconst OP_SORTER_NEXT: &str = \"SorterNext\";\nconst OP_SORTER_OPEN: &str = \"SorterOpen\";\nconst OP_SORTER_SORT: &str = \"SorterSort\";\nconst OP_V_FILTER: &str = \"VFilter\";\nconst OP_V_NEXT: &str = \"VNext\";\nconst OP_YIELD: &str = \"Yield\";\nconst OP_JUMP: &str = \"Jump\";\nconst OP_COLUMN: &str = \"Column\";\nconst OP_MAKE_RECORD: &str = \"MakeRecord\";\nconst OP_INSERT: &str = \"Insert\";\nconst OP_IDX_INSERT: &str = \"IdxInsert\";\nconst OP_OPEN_DUP: &str = \"OpenDup\";\nconst OP_OPEN_PSEUDO: &str = \"OpenPseudo\";\nconst OP_OPEN_READ: &str = \"OpenRead\";\nconst OP_OPEN_WRITE: &str = \"OpenWrite\";\nconst OP_OPEN_EPHEMERAL: &str = \"OpenEphemeral\";\nconst OP_OPEN_AUTOINDEX: &str = \"OpenAutoindex\";\nconst OP_AGG_FINAL: &str = \"AggFinal\";\nconst OP_AGG_VALUE: &str = \"AggValue\";\nconst OP_AGG_STEP: &str = \"AggStep\";\nconst OP_FUNCTION: &str = \"Function\";\nconst OP_MOVE: &str = \"Move\";\nconst OP_COPY: &str = \"Copy\";\nconst OP_SCOPY: &str = \"SCopy\";\nconst OP_NULL: &str = \"Null\";\nconst OP_NULL_ROW: &str = \"NullRow\";\nconst OP_INT_COPY: &str = \"IntCopy\";\nconst OP_CAST: &str = \"Cast\";\nconst OP_STRING8: &str = \"String8\";\nconst OP_INT64: &str = \"Int64\";\nconst OP_INTEGER: &str = \"Integer\";\nconst OP_REAL: &str = \"Real\";\nconst OP_NOT: &str = \"Not\";\nconst OP_BLOB: &str = \"Blob\";\nconst OP_VARIABLE: &str = \"Variable\";\nconst OP_COUNT: &str = \"Count\";\nconst OP_ROWID: &str = \"Rowid\";\nconst OP_NEWROWID: &str = \"NewRowid\";\nconst OP_OR: &str = \"Or\";\nconst OP_AND: &str = \"And\";\nconst OP_BIT_AND: &str = \"BitAnd\";\nconst OP_BIT_OR: &str = \"BitOr\";\nconst OP_SHIFT_LEFT: &str = \"ShiftLeft\";\nconst OP_SHIFT_RIGHT: &str = \"ShiftRight\";\nconst OP_ADD: &str = \"Add\";\nconst OP_SUBTRACT: &str = \"Subtract\";\nconst OP_MULTIPLY: &str = \"Multiply\";\nconst OP_DIVIDE: &str = \"Divide\";\nconst OP_REMAINDER: &str = \"Remainder\";\nconst OP_CONCAT: &str = \"Concat\";\nconst OP_OFFSET_LIMIT: &str = \"OffsetLimit\";\nconst OP_RESULT_ROW: &str = \"ResultRow\";\nconst OP_HALT: &str = \"Halt\";\nconst OP_HALT_IF_NULL: &str = \"HaltIfNull\";\n\nconst MAX_LOOP_COUNT: u8 = 2;\nconst MAX_TOTAL_INSTRUCTION_COUNT: u32 = 100_000;\n\n#[derive(Clone, Eq, PartialEq, Hash)]\nenum ColumnType {\n    Single {\n        datatype: DataType,\n        nullable: Option<bool>,\n    },\n    Record(IntMap<ColumnType>),\n}\n\nimpl Default for ColumnType {\n    fn default() -> Self {\n        Self::Single {\n            datatype: DataType::Null,\n            nullable: None,\n        }\n    }\n}\n\nimpl ColumnType {\n    fn null() -> Self {\n        Self::Single {\n            datatype: DataType::Null,\n            nullable: Some(true),\n        }\n    }\n    fn map_to_datatype(&self) -> DataType {\n        match self {\n            Self::Single { datatype, .. } => *datatype,\n            Self::Record(_) => DataType::Null, //If we're trying to coerce to a regular Datatype, we can assume a Record is invalid for the context\n        }\n    }\n    fn map_to_nullable(&self) -> Option<bool> {\n        match self {\n            Self::Single { nullable, .. } => *nullable,\n            Self::Record(_) => None, //If we're trying to coerce to a regular Datatype, we can assume a Record is invalid for the context\n        }\n    }\n}\n\nimpl core::fmt::Debug for ColumnType {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        match self {\n            Self::Single { datatype, nullable } => {\n                let nullable_str = match nullable {\n                    Some(true) => \"NULL\",\n                    Some(false) => \"NOT NULL\",\n                    None => \"NULL?\",\n                };\n                write!(f, \"{:?} {}\", datatype, nullable_str)\n            }\n            Self::Record(columns) => {\n                f.write_str(\"Record(\")?;\n                let mut column_iter = columns.iter();\n                if let Some(item) = column_iter.next() {\n                    write!(f, \"{:?}\", item)?;\n                    for item in column_iter {\n                        write!(f, \", {:?}\", item)?;\n                    }\n                }\n                f.write_str(\")\")\n            }\n        }\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Hash)]\nenum RegDataType {\n    Single(ColumnType),\n    Int(i64),\n}\n\nimpl RegDataType {\n    fn map_to_datatype(&self) -> DataType {\n        match self {\n            RegDataType::Single(d) => d.map_to_datatype(),\n            RegDataType::Int(_) => DataType::Integer,\n        }\n    }\n    fn map_to_nullable(&self) -> Option<bool> {\n        match self {\n            RegDataType::Single(d) => d.map_to_nullable(),\n            RegDataType::Int(_) => Some(false),\n        }\n    }\n    fn map_to_columntype(&self) -> ColumnType {\n        match self {\n            RegDataType::Single(d) => d.clone(),\n            RegDataType::Int(_) => ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(false),\n            },\n        }\n    }\n}\n\nimpl Default for RegDataType {\n    fn default() -> Self {\n        Self::Single(ColumnType::default())\n    }\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Hash)]\nstruct TableDataType {\n    cols: IntMap<ColumnType>,\n    is_empty: Option<bool>,\n}\n\n#[derive(Debug, Clone, Eq, PartialEq, Hash)]\nenum CursorDataType {\n    Normal(i64),\n    Pseudo(i64),\n}\n\nimpl CursorDataType {\n    fn columns(\n        &self,\n        tables: &IntMap<TableDataType>,\n        registers: &IntMap<RegDataType>,\n    ) -> IntMap<ColumnType> {\n        match self {\n            Self::Normal(i) => match tables.get(i) {\n                Some(tab) => tab.cols.clone(),\n                None => IntMap::new(),\n            },\n            Self::Pseudo(i) => match registers.get(i) {\n                Some(RegDataType::Single(ColumnType::Record(r))) => r.clone(),\n                _ => IntMap::new(),\n            },\n        }\n    }\n\n    fn columns_ref<'s, 'r, 'o>(\n        &'s self,\n        tables: &'r IntMap<TableDataType>,\n        registers: &'r IntMap<RegDataType>,\n    ) -> Option<&'o IntMap<ColumnType>>\n    where\n        's: 'o,\n        'r: 'o,\n    {\n        match self {\n            Self::Normal(i) => match tables.get(i) {\n                Some(tab) => Some(&tab.cols),\n                None => None,\n            },\n            Self::Pseudo(i) => match registers.get(i) {\n                Some(RegDataType::Single(ColumnType::Record(r))) => Some(r),\n                _ => None,\n            },\n        }\n    }\n\n    fn columns_mut<'s, 'r, 'o>(\n        &'s self,\n        tables: &'r mut IntMap<TableDataType>,\n        registers: &'r mut IntMap<RegDataType>,\n    ) -> Option<&'o mut IntMap<ColumnType>>\n    where\n        's: 'o,\n        'r: 'o,\n    {\n        match self {\n            Self::Normal(i) => match tables.get_mut(i) {\n                Some(tab) => Some(&mut tab.cols),\n                None => None,\n            },\n            Self::Pseudo(i) => match registers.get_mut(i) {\n                Some(RegDataType::Single(ColumnType::Record(r))) => Some(r),\n                _ => None,\n            },\n        }\n    }\n\n    fn table_mut<'s, 'r, 'o>(\n        &'s self,\n        tables: &'r mut IntMap<TableDataType>,\n    ) -> Option<&'o mut TableDataType>\n    where\n        's: 'o,\n        'r: 'o,\n    {\n        match self {\n            Self::Normal(i) => match tables.get_mut(i) {\n                Some(tab) => Some(tab),\n                None => None,\n            },\n            _ => None,\n        }\n    }\n\n    fn is_empty(&self, tables: &IntMap<TableDataType>) -> Option<bool> {\n        match self {\n            Self::Normal(i) => match tables.get(i) {\n                Some(tab) => tab.is_empty,\n                None => Some(true),\n            },\n            Self::Pseudo(_) => Some(false), //pseudo cursors have exactly one row\n        }\n    }\n}\n\n#[allow(clippy::wildcard_in_or_patterns)]\nfn affinity_to_type(affinity: u8) -> DataType {\n    match affinity {\n        SQLITE_AFF_BLOB => DataType::Blob,\n        SQLITE_AFF_INTEGER => DataType::Integer,\n        SQLITE_AFF_NUMERIC => DataType::Numeric,\n        SQLITE_AFF_REAL => DataType::Float,\n        SQLITE_AFF_TEXT => DataType::Text,\n\n        SQLITE_AFF_NONE | _ => DataType::Null,\n    }\n}\n\n#[allow(clippy::wildcard_in_or_patterns)]\nfn opcode_to_type(op: &str) -> DataType {\n    match op {\n        OP_REAL => DataType::Float,\n        OP_BLOB => DataType::Blob,\n        OP_AND | OP_OR => DataType::Bool,\n        OP_NEWROWID | OP_ROWID | OP_COUNT | OP_INT64 | OP_INTEGER => DataType::Integer,\n        OP_STRING8 => DataType::Text,\n        OP_COLUMN | _ => DataType::Null,\n    }\n}\n\nfn root_block_columns(\n    conn: &mut ConnectionState,\n) -> Result<HashMap<(i64, i64), IntMap<ColumnType>>, Error> {\n    let table_block_columns: Vec<(i64, i64, i64, String, bool)> = execute::iter(\n        conn,\n        \"SELECT s.dbnum, s.rootpage, col.cid as colnum, col.type, col.\\\"notnull\\\"\n         FROM (\n             select 1 dbnum, tss.* from temp.sqlite_schema tss\n             UNION ALL select 0 dbnum, mss.* from main.sqlite_schema mss\n             ) s\n         JOIN pragma_table_info(s.name) AS col\n         WHERE s.type = 'table'\n         UNION ALL\n         SELECT s.dbnum, s.rootpage, idx.seqno as colnum, col.type, col.\\\"notnull\\\"\n         FROM (\n             select 1 dbnum, tss.* from temp.sqlite_schema tss\n             UNION ALL select 0 dbnum, mss.* from main.sqlite_schema mss\n             ) s\n         JOIN pragma_index_info(s.name) AS idx\n         LEFT JOIN pragma_table_info(s.tbl_name) as col\n           ON col.cid = idx.cid\n           WHERE s.type = 'index'\",\n        None,\n        false,\n    )?\n    .filter_map(|res| res.map(|either| either.right()).transpose())\n    .map(|row| FromRow::from_row(&row?))\n    .collect::<Result<Vec<_>, Error>>()?;\n\n    let mut row_info: HashMap<(i64, i64), IntMap<ColumnType>> = HashMap::new();\n    for (dbnum, block, colnum, datatype, notnull) in table_block_columns {\n        let row_info = row_info.entry((dbnum, block)).or_default();\n        row_info.insert(\n            colnum,\n            ColumnType::Single {\n                datatype: datatype.parse().unwrap_or(DataType::Null),\n                nullable: Some(!notnull),\n            },\n        );\n    }\n\n    Ok(row_info)\n}\n\nstruct Sequence(i64);\n\nimpl Sequence {\n    pub fn new() -> Self {\n        Self(0)\n    }\n    pub fn next(&mut self) -> i64 {\n        let curr = self.0;\n        self.0 += 1;\n        curr\n    }\n}\n\n#[derive(Debug)]\nstruct QueryState {\n    // The number of times each instruction has been visited\n    pub visited: Vec<u8>,\n    // A unique identifier of the query branch\n    pub branch_id: i64,\n    // How many instructions have been executed on this branch (NOT the same as program_i, which is the currently executing instruction of the program)\n    pub instruction_counter: i64,\n    // Parent branch this branch was forked from (if any)\n    pub branch_parent: Option<BranchParent>,\n    // State of the virtual machine\n    pub mem: MemoryState,\n    // Results published by the execution\n    pub result: Option<Vec<(Option<SqliteTypeInfo>, Option<bool>)>>,\n}\n\nimpl From<&QueryState> for MemoryState {\n    fn from(val: &QueryState) -> Self {\n        val.mem.clone()\n    }\n}\n\nimpl From<QueryState> for MemoryState {\n    fn from(val: QueryState) -> Self {\n        val.mem\n    }\n}\n\nimpl From<&QueryState> for BranchParent {\n    fn from(val: &QueryState) -> Self {\n        Self {\n            id: val.branch_id,\n            idx: val.instruction_counter,\n        }\n    }\n}\n\nimpl QueryState {\n    fn get_reference(&self) -> BranchParent {\n        BranchParent {\n            id: self.branch_id,\n            idx: self.instruction_counter,\n        }\n    }\n    fn new_branch(&self, branch_seq: &mut Sequence) -> Self {\n        Self {\n            visited: self.visited.clone(),\n            branch_id: branch_seq.next(),\n            instruction_counter: 0,\n            branch_parent: Some(BranchParent {\n                id: self.branch_id,\n                idx: self.instruction_counter - 1, //instruction counter is incremented at the start of processing an instruction, so need to subtract 1 to get the 'current' instruction\n            }),\n            mem: self.mem.clone(),\n            result: self.result.clone(),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Hash)]\nstruct MemoryState {\n    // Next instruction to execute\n    pub program_i: usize,\n    // Registers\n    pub r: IntMap<RegDataType>,\n    // Rows that pointers point to\n    pub p: IntMap<CursorDataType>,\n    // Table definitions pointed to by pointers\n    pub t: IntMap<TableDataType>,\n}\n\nimpl DebugDiff for MemoryState {\n    fn diff(&self, prev: &Self) -> String {\n        let r_diff = self.r.diff(&prev.r);\n        let p_diff = self.p.diff(&prev.p);\n        let t_diff = self.t.diff(&prev.t);\n\n        let mut differences = String::new();\n        for (i, v) in r_diff {\n            if !differences.is_empty() {\n                differences.push('\\n');\n            }\n            differences.push_str(&format!(\"r[{}]={:?}\", i, v))\n        }\n        for (i, v) in p_diff {\n            if !differences.is_empty() {\n                differences.push('\\n');\n            }\n            differences.push_str(&format!(\"p[{}]={:?}\", i, v))\n        }\n        for (i, v) in t_diff {\n            if !differences.is_empty() {\n                differences.push('\\n');\n            }\n            differences.push_str(&format!(\"t[{}]={:?}\", i, v))\n        }\n        differences\n    }\n}\n\nstruct BranchList {\n    states: Vec<QueryState>,\n    visited_branch_state: HashMap<MemoryState, BranchParent>,\n}\n\nimpl BranchList {\n    pub fn new(state: QueryState) -> Self {\n        Self {\n            states: vec![state],\n            visited_branch_state: HashMap::new(),\n        }\n    }\n    pub fn push<R: Debug, P: Debug>(\n        &mut self,\n        mut state: QueryState,\n        logger: &mut crate::logger::QueryPlanLogger<'_, R, MemoryState, P>,\n    ) {\n        logger.add_branch(&state, &state.branch_parent.unwrap());\n        match self.visited_branch_state.entry(state.mem) {\n            hash_map::Entry::Vacant(entry) => {\n                //this state is not identical to another state, so it will need to be processed\n                state.mem = entry.key().clone(); //replace state.mem since .entry() moved it\n                entry.insert(state.get_reference());\n                self.states.push(state);\n            }\n            hash_map::Entry::Occupied(entry) => {\n                //already saw a state identical to this one, so no point in processing it\n                state.mem = entry.key().clone(); //replace state.mem since .entry() moved it\n                logger.add_result(state, BranchResult::Dedup(*entry.get()));\n            }\n        }\n    }\n    pub fn pop(&mut self) -> Option<QueryState> {\n        self.states.pop()\n    }\n}\n\n// Opcode Reference: https://sqlite.org/opcode.html\npub(super) fn explain(\n    conn: &mut ConnectionState,\n    query: &str,\n) -> Result<(Vec<SqliteTypeInfo>, Vec<Option<bool>>), Error> {\n    let root_block_cols = root_block_columns(conn)?;\n    let program: Vec<(i64, String, i64, i64, i64, Vec<u8>)> =\n        execute::iter(conn, AssertSqlSafe(format!(\"EXPLAIN {query}\")), None, false)?\n            .filter_map(|res| res.map(|either| either.right()).transpose())\n            .map(|row| FromRow::from_row(&row?))\n            .collect::<Result<Vec<_>, Error>>()?;\n    let program_size = program.len();\n\n    let mut logger = crate::logger::QueryPlanLogger::new(query, &program);\n    let mut branch_seq = Sequence::new();\n    let mut states = BranchList::new(QueryState {\n        visited: vec![0; program_size],\n        branch_id: branch_seq.next(),\n        branch_parent: None,\n        instruction_counter: 0,\n        result: None,\n        mem: MemoryState {\n            program_i: 0,\n            r: IntMap::new(),\n            t: IntMap::new(),\n            p: IntMap::new(),\n        },\n    });\n\n    let mut gas = MAX_TOTAL_INSTRUCTION_COUNT;\n    let mut result_states = Vec::new();\n\n    while let Some(mut state) = states.pop() {\n        while state.mem.program_i < program_size {\n            let (_, ref opcode, p1, p2, p3, ref p4) = program[state.mem.program_i];\n\n            logger.add_operation(state.mem.program_i, &state);\n            state.instruction_counter += 1;\n\n            //limit the number of 'instructions' that can be evaluated\n            if gas > 0 {\n                gas -= 1;\n            } else {\n                logger.add_result(state, BranchResult::GasLimit);\n                break;\n            }\n\n            if state.visited[state.mem.program_i] > MAX_LOOP_COUNT {\n                logger.add_result(state, BranchResult::LoopLimit);\n                //avoid (infinite) loops by breaking if we ever hit the same instruction twice\n                break;\n            }\n\n            state.visited[state.mem.program_i] += 1;\n\n            match &**opcode {\n                OP_INIT => {\n                    // start at <p2>\n                    state.mem.program_i = p2 as usize;\n                    continue;\n                }\n\n                OP_GOTO => {\n                    // goto <p2>\n\n                    state.mem.program_i = p2 as usize;\n                    continue;\n                }\n\n                OP_GO_SUB => {\n                    // store current instruction in r[p1], goto <p2>\n                    state\n                        .mem\n                        .r\n                        .insert(p1, RegDataType::Int(state.mem.program_i as i64));\n                    state.mem.program_i = p2 as usize;\n                    continue;\n                }\n\n                OP_FK_IF_ZERO => {\n                    // goto <p2> if no constraints are unsatisfied (assumed to be true)\n\n                    state.mem.program_i = p2 as usize;\n                    continue;\n                }\n\n                OP_DECR_JUMP_ZERO | OP_ELSE_EQ | OP_EQ | OP_FILTER | OP_FOUND | OP_GE | OP_GT\n                | OP_IDX_GE | OP_IDX_GT | OP_IDX_LE | OP_IDX_LT | OP_IF_NO_HOPE | OP_IF_NOT\n                | OP_IF_NOT_OPEN | OP_IF_NOT_ZERO | OP_IF_NULL_ROW | OP_IF_SMALLER\n                | OP_INCR_VACUUM | OP_IS_NULL_OR_TYPE | OP_LE | OP_LT | OP_NE | OP_NEXT\n                | OP_NO_CONFLICT | OP_NOT_EXISTS | OP_ONCE | OP_PREV | OP_PROGRAM\n                | OP_ROW_SET_READ | OP_ROW_SET_TEST | OP_SEEK_GE | OP_SEEK_GT | OP_SEEK_LE\n                | OP_SEEK_LT | OP_SEEK_ROW_ID | OP_SEEK_SCAN | OP_SEQUENCE_TEST\n                | OP_SORTER_NEXT | OP_V_FILTER | OP_V_NEXT => {\n                    // goto <p2> or next instruction (depending on actual values)\n\n                    let mut branch_state = state.new_branch(&mut branch_seq);\n                    branch_state.mem.program_i = p2 as usize;\n                    states.push(branch_state, &mut logger);\n\n                    state.mem.program_i += 1;\n                    continue;\n                }\n\n                OP_IS_NULL => {\n                    // goto <p2> if p1 is null\n\n                    //branch if maybe null\n                    let might_branch = match state.mem.r.get(&p1) {\n                        Some(r_p1) => !matches!(r_p1.map_to_nullable(), Some(false)),\n                        _ => false,\n                    };\n\n                    //nobranch if maybe not null\n                    let might_not_branch = match state.mem.r.get(&p1) {\n                        Some(r_p1) => !matches!(r_p1.map_to_datatype(), DataType::Null),\n                        _ => false,\n                    };\n\n                    if might_branch {\n                        let mut branch_state = state.new_branch(&mut branch_seq);\n                        branch_state.mem.program_i = p2 as usize;\n                        branch_state\n                            .mem\n                            .r\n                            .insert(p1, RegDataType::Single(ColumnType::default()));\n\n                        states.push(branch_state, &mut logger);\n                    }\n\n                    if might_not_branch {\n                        state.mem.program_i += 1;\n                        if let Some(RegDataType::Single(ColumnType::Single { nullable, .. })) =\n                            state.mem.r.get_mut(&p1)\n                        {\n                            *nullable = Some(false);\n                        }\n                        continue;\n                    } else {\n                        logger.add_result(state, BranchResult::Branched);\n                        break;\n                    }\n                }\n\n                OP_NOT_NULL => {\n                    // goto <p2> if p1 is not null\n\n                    let might_branch = match state.mem.r.get(&p1) {\n                        Some(r_p1) => !matches!(r_p1.map_to_datatype(), DataType::Null),\n                        _ => false,\n                    };\n\n                    let might_not_branch = match state.mem.r.get(&p1) {\n                        Some(r_p1) => !matches!(r_p1.map_to_nullable(), Some(false)),\n                        _ => false,\n                    };\n\n                    if might_branch {\n                        let mut branch_state = state.new_branch(&mut branch_seq);\n                        branch_state.mem.program_i = p2 as usize;\n                        if let Some(RegDataType::Single(ColumnType::Single { nullable, .. })) =\n                            branch_state.mem.r.get_mut(&p1)\n                        {\n                            *nullable = Some(false);\n                        }\n\n                        states.push(branch_state, &mut logger);\n                    }\n\n                    if might_not_branch {\n                        state.mem.program_i += 1;\n                        state\n                            .mem\n                            .r\n                            .insert(p1, RegDataType::Single(ColumnType::default()));\n                        continue;\n                    } else {\n                        logger.add_result(state, BranchResult::Branched);\n                        break;\n                    }\n                }\n\n                OP_MUST_BE_INT => {\n                    // if p1 can be coerced to int, continue\n                    // if p1 cannot be coerced to int, error if p2 == 0, else jump to p2\n\n                    //don't bother checking actual types, just don't branch to instruction 0\n                    if p2 != 0 {\n                        let mut branch_state = state.new_branch(&mut branch_seq);\n                        branch_state.mem.program_i = p2 as usize;\n                        states.push(branch_state, &mut logger);\n                    }\n\n                    state.mem.program_i += 1;\n                    continue;\n                }\n\n                OP_IF => {\n                    // goto <p2> if r[p1] is true (1) or r[p1] is null and p3 is nonzero\n\n                    let might_branch = match state.mem.r.get(&p1) {\n                        Some(RegDataType::Int(r_p1)) => *r_p1 != 0,\n                        _ => true,\n                    };\n\n                    let might_not_branch = match state.mem.r.get(&p1) {\n                        Some(RegDataType::Int(r_p1)) => *r_p1 == 0,\n                        _ => true,\n                    };\n\n                    if might_branch {\n                        let mut branch_state = state.new_branch(&mut branch_seq);\n                        branch_state.mem.program_i = p2 as usize;\n                        if p3 == 0 {\n                            branch_state.mem.r.insert(p1, RegDataType::Int(1));\n                        }\n\n                        states.push(branch_state, &mut logger);\n                    }\n\n                    if might_not_branch {\n                        state.mem.program_i += 1;\n                        if p3 == 0 {\n                            state.mem.r.insert(p1, RegDataType::Int(0));\n                        }\n                        continue;\n                    } else {\n                        logger.add_result(state, BranchResult::Branched);\n                        break;\n                    }\n                }\n\n                OP_IF_POS => {\n                    // goto <p2> if r[p1] is true (1) or r[p1] is null and p3 is nonzero\n\n                    // as a workaround for large offset clauses, both branches will be attempted after 1 loop\n\n                    let might_branch = match state.mem.r.get(&p1) {\n                        Some(RegDataType::Int(r_p1)) => *r_p1 >= 1,\n                        _ => true,\n                    };\n\n                    let might_not_branch = match state.mem.r.get(&p1) {\n                        Some(RegDataType::Int(r_p1)) => *r_p1 < 1,\n                        _ => true,\n                    };\n\n                    let loop_detected = state.visited[state.mem.program_i] > 1;\n                    if might_branch || loop_detected {\n                        let mut branch_state = state.new_branch(&mut branch_seq);\n                        branch_state.mem.program_i = p2 as usize;\n                        if let Some(RegDataType::Int(r_p1)) = branch_state.mem.r.get_mut(&p1) {\n                            *r_p1 -= 1;\n                        }\n                        states.push(branch_state, &mut logger);\n                    }\n\n                    if might_not_branch {\n                        state.mem.program_i += 1;\n                        continue;\n                    } else if loop_detected {\n                        state.mem.program_i += 1;\n                        if matches!(state.mem.r.get_mut(&p1), Some(RegDataType::Int(..))) {\n                            //forget the exact value, in case some later cares\n                            state.mem.r.insert(\n                                p1,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype: DataType::Integer,\n                                    nullable: Some(false),\n                                }),\n                            );\n                        }\n                        continue;\n                    } else {\n                        logger.add_result(state, BranchResult::Branched);\n                        break;\n                    }\n                }\n\n                OP_REWIND | OP_LAST | OP_SORT | OP_SORTER_SORT => {\n                    // goto <p2> if cursor p1 is empty and p2 != 0, else next instruction\n\n                    if p2 == 0 {\n                        state.mem.program_i += 1;\n                        continue;\n                    }\n\n                    if let Some(cursor) = state.mem.p.get(&p1) {\n                        if matches!(cursor.is_empty(&state.mem.t), None | Some(true)) {\n                            //only take this branch if the cursor is empty\n\n                            let mut branch_state = state.new_branch(&mut branch_seq);\n                            branch_state.mem.program_i = p2 as usize;\n\n                            if let Some(cur) = branch_state.mem.p.get(&p1) {\n                                if let Some(tab) = cur.table_mut(&mut branch_state.mem.t) {\n                                    tab.is_empty = Some(true);\n                                }\n                            }\n                            states.push(branch_state, &mut logger);\n                        }\n\n                        if matches!(cursor.is_empty(&state.mem.t), None | Some(false)) {\n                            //only take this branch if the cursor is non-empty\n                            state.mem.program_i += 1;\n                            continue;\n                        } else {\n                            logger.add_result(state, BranchResult::Branched);\n                            break;\n                        }\n                    }\n\n                    logger.add_result(state, BranchResult::Branched);\n                    break;\n                }\n\n                OP_INIT_COROUTINE => {\n                    // goto <p2> or next instruction (depending on actual values)\n\n                    state.mem.r.insert(p1, RegDataType::Int(p3));\n\n                    if p2 != 0 {\n                        state.mem.program_i = p2 as usize;\n                    } else {\n                        state.mem.program_i += 1;\n                    }\n                    continue;\n                }\n\n                OP_END_COROUTINE => {\n                    // jump to p2 of the yield instruction pointed at by register p1\n\n                    if let Some(RegDataType::Int(yield_i)) = state.mem.r.get(&p1) {\n                        if let Some((_, yield_op, _, yield_p2, _, _)) =\n                            program.get(*yield_i as usize)\n                        {\n                            if OP_YIELD == yield_op.as_str() {\n                                state.mem.program_i = (*yield_p2) as usize;\n                                state.mem.r.remove(&p1);\n                                continue;\n                            } else {\n                                logger.add_result(state, BranchResult::Error);\n                                break;\n                            }\n                        } else {\n                            logger.add_result(state, BranchResult::Error);\n                            break;\n                        }\n                    } else {\n                        logger.add_result(state, BranchResult::Error);\n                        break;\n                    }\n                }\n\n                OP_RETURN => {\n                    // jump to the instruction after the instruction pointed at by register p1\n\n                    if let Some(RegDataType::Int(return_i)) = state.mem.r.get(&p1) {\n                        state.mem.program_i = (*return_i + 1) as usize;\n                        state.mem.r.remove(&p1);\n                        continue;\n                    } else if p3 == 1 {\n                        state.mem.program_i += 1;\n                        continue;\n                    } else {\n                        logger.add_result(state, BranchResult::Error);\n                        break;\n                    }\n                }\n\n                OP_YIELD => {\n                    // jump to p2 of the yield instruction pointed at by register p1, store prior instruction in p1\n\n                    if let Some(RegDataType::Int(yield_i)) = state.mem.r.get_mut(&p1) {\n                        let program_i: usize = state.mem.program_i;\n\n                        //if yielding to a yield operation, go to the NEXT instruction after that instruction\n                        if program\n                            .get(*yield_i as usize)\n                            .map(|(_, yield_op, _, _, _, _)| yield_op.as_str())\n                            == Some(OP_YIELD)\n                        {\n                            state.mem.program_i = (*yield_i + 1) as usize;\n                            *yield_i = program_i as i64;\n                            continue;\n                        } else {\n                            state.mem.program_i = *yield_i as usize;\n                            *yield_i = program_i as i64;\n                            continue;\n                        }\n                    } else {\n                        logger.add_result(state, BranchResult::Error);\n                        break;\n                    }\n                }\n\n                OP_JUMP => {\n                    // goto one of <p1>, <p2>, or <p3> based on the result of a prior compare\n\n                    let mut branch_state = state.new_branch(&mut branch_seq);\n                    branch_state.mem.program_i = p1 as usize;\n                    states.push(branch_state, &mut logger);\n\n                    let mut branch_state = state.new_branch(&mut branch_seq);\n                    branch_state.mem.program_i = p2 as usize;\n                    states.push(branch_state, &mut logger);\n\n                    let mut branch_state = state.new_branch(&mut branch_seq);\n                    branch_state.mem.program_i = p3 as usize;\n                    states.push(branch_state, &mut logger);\n                }\n\n                OP_COLUMN => {\n                    //Get the row stored at p1, or NULL; get the column stored at p2, or NULL\n                    let value: ColumnType = state\n                        .mem\n                        .p\n                        .get(&p1)\n                        .and_then(|c| c.columns_ref(&state.mem.t, &state.mem.r))\n                        .and_then(|cc| cc.get(&p2))\n                        .cloned()\n                        .unwrap_or_default();\n\n                    // insert into p3 the datatype of the col\n                    state.mem.r.insert(p3, RegDataType::Single(value));\n                }\n\n                OP_SEQUENCE => {\n                    //Copy sequence number from cursor p1 to register p2, increment cursor p1 sequence number\n\n                    //Cursor emulation doesn't sequence value, but it is an int\n                    state.mem.r.insert(\n                        p2,\n                        RegDataType::Single(ColumnType::Single {\n                            datatype: DataType::Integer,\n                            nullable: Some(false),\n                        }),\n                    );\n                }\n\n                OP_ROW_DATA | OP_SORTER_DATA => {\n                    //Get entire row from cursor p1, store it into register p2\n                    if let Some(record) = state\n                        .mem\n                        .p\n                        .get(&p1)\n                        .map(|c| c.columns(&state.mem.t, &state.mem.r))\n                    {\n                        state\n                            .mem\n                            .r\n                            .insert(p2, RegDataType::Single(ColumnType::Record(record)));\n                    } else {\n                        state\n                            .mem\n                            .r\n                            .insert(p2, RegDataType::Single(ColumnType::Record(IntMap::new())));\n                    }\n                }\n\n                OP_MAKE_RECORD => {\n                    // p3 = Record([p1 .. p1 + p2])\n                    let mut record = Vec::with_capacity(p2 as usize);\n                    for reg in p1..p1 + p2 {\n                        record.push(\n                            state\n                                .mem\n                                .r\n                                .get(&reg)\n                                .map(|d| d.map_to_columntype())\n                                .unwrap_or(ColumnType::default()),\n                        );\n                    }\n                    state.mem.r.insert(\n                        p3,\n                        RegDataType::Single(ColumnType::Record(IntMap::from_dense_record(&record))),\n                    );\n                }\n\n                OP_INSERT | OP_IDX_INSERT | OP_SORTER_INSERT => {\n                    if let Some(RegDataType::Single(columntype)) = state.mem.r.get(&p2) {\n                        match columntype {\n                            ColumnType::Record(record) => {\n                                if let Some(TableDataType { cols, is_empty }) = state\n                                    .mem\n                                    .p\n                                    .get(&p1)\n                                    .and_then(|cur| cur.table_mut(&mut state.mem.t))\n                                {\n                                    // Insert the record into wherever pointer p1 is\n                                    *cols = record.clone();\n                                    *is_empty = Some(false);\n                                }\n                            }\n                            ColumnType::Single {\n                                datatype: DataType::Null,\n                                nullable: _,\n                            } => {\n                                if let Some(TableDataType { is_empty, .. }) = state\n                                    .mem\n                                    .p\n                                    .get(&p1)\n                                    .and_then(|cur| cur.table_mut(&mut state.mem.t))\n                                {\n                                    // Insert a null record into wherever pointer p1 is\n                                    *is_empty = Some(false);\n                                }\n                            }\n                            _ => {}\n                        }\n                    }\n                    //Noop if the register p2 isn't a record, or if pointer p1 does not exist\n                }\n\n                OP_DELETE => {\n                    // delete a record from cursor p1\n                    if let Some(TableDataType { is_empty, .. }) = state\n                        .mem\n                        .p\n                        .get(&p1)\n                        .and_then(|cur| cur.table_mut(&mut state.mem.t))\n                    {\n                        if *is_empty == Some(false) {\n                            *is_empty = None; //the cursor might be empty now\n                        }\n                    }\n                }\n\n                OP_OPEN_PSEUDO => {\n                    // Create a cursor p1 aliasing the record from register p2\n                    state.mem.p.insert(p1, CursorDataType::Pseudo(p2));\n                }\n\n                OP_OPEN_DUP => {\n                    if let Some(cur) = state.mem.p.get(&p2) {\n                        state.mem.p.insert(p1, cur.clone());\n                    }\n                }\n\n                OP_OPEN_READ | OP_OPEN_WRITE => {\n                    //Create a new pointer which is referenced by p1, take column metadata from db schema if found\n                    let table_info = if p3 == 0 || p3 == 1 {\n                        if let Some(columns) = root_block_cols.get(&(p3, p2)) {\n                            TableDataType {\n                                cols: columns.clone(),\n                                is_empty: None,\n                            }\n                        } else {\n                            TableDataType {\n                                cols: IntMap::new(),\n                                is_empty: None,\n                            }\n                        }\n                    } else {\n                        TableDataType {\n                            cols: IntMap::new(),\n                            is_empty: None,\n                        }\n                    };\n\n                    state.mem.t.insert(state.mem.program_i as i64, table_info);\n                    state\n                        .mem\n                        .p\n                        .insert(p1, CursorDataType::Normal(state.mem.program_i as i64));\n                }\n\n                OP_OPEN_EPHEMERAL | OP_OPEN_AUTOINDEX | OP_SORTER_OPEN => {\n                    //Create a new pointer which is referenced by p1\n                    let table_info = TableDataType {\n                        cols: IntMap::from_elem(ColumnType::null(), p2 as usize),\n                        is_empty: Some(true),\n                    };\n\n                    state.mem.t.insert(state.mem.program_i as i64, table_info);\n                    state\n                        .mem\n                        .p\n                        .insert(p1, CursorDataType::Normal(state.mem.program_i as i64));\n                }\n\n                OP_VARIABLE => {\n                    // r[p2] = <value of variable>\n                    state\n                        .mem\n                        .r\n                        .insert(p2, RegDataType::Single(ColumnType::null()));\n                }\n\n                // if there is a value in p3, and the query passes, then\n                // we know that it is not nullable\n                OP_HALT_IF_NULL => {\n                    if let Some(RegDataType::Single(ColumnType::Single { nullable, .. })) =\n                        state.mem.r.get_mut(&p3)\n                    {\n                        *nullable = Some(false);\n                    }\n                }\n\n                OP_FUNCTION => {\n                    // r[p3] = func( _ ), registered function name is in p4\n                    match from_utf8(p4).map_err(Error::protocol)? {\n                        \"last_insert_rowid(0)\" => {\n                            // last_insert_rowid() -> INTEGER\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype: DataType::Integer,\n                                    nullable: Some(false),\n                                }),\n                            );\n                        }\n                        \"date(-1)\" | \"time(-1)\" | \"datetime(-1)\" | \"strftime(-1)\" => {\n                            // date|time|datetime|strftime(...) -> TEXT\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype: DataType::Text,\n                                    nullable: Some(p2 != 0), //never a null result if no argument provided\n                                }),\n                            );\n                        }\n                        \"julianday(-1)\" => {\n                            // julianday(...) -> REAL\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype: DataType::Float,\n                                    nullable: Some(p2 != 0), //never a null result if no argument provided\n                                }),\n                            );\n                        }\n                        \"unixepoch(-1)\" => {\n                            // unixepoch(p2...) -> INTEGER\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype: DataType::Integer,\n                                    nullable: Some(p2 != 0), //never a null result if no argument provided\n                                }),\n                            );\n                        }\n\n                        _ => logger.add_unknown_operation(state.mem.program_i),\n                    }\n                }\n\n                OP_NULL_ROW => {\n                    // all columns in cursor X are potentially nullable\n                    if let Some(cols) = state\n                        .mem\n                        .p\n                        .get_mut(&p1)\n                        .and_then(|c| c.columns_mut(&mut state.mem.t, &mut state.mem.r))\n                    {\n                        for col in cols.values_mut() {\n                            if let ColumnType::Single {\n                                ref mut nullable, ..\n                            } = col\n                            {\n                                *nullable = Some(true);\n                            }\n                        }\n                    }\n                    //else we don't know about the cursor\n                }\n\n                OP_AGG_STEP | OP_AGG_VALUE => {\n                    //assume that AGG_FINAL will be called\n                    let p4 = from_utf8(p4).map_err(Error::protocol)?;\n\n                    if p4.starts_with(\"count(\")\n                        || p4.starts_with(\"row_number(\")\n                        || p4.starts_with(\"rank(\")\n                        || p4.starts_with(\"dense_rank(\")\n                        || p4.starts_with(\"ntile(\")\n                    {\n                        // count(_) -> INTEGER\n                        state.mem.r.insert(\n                            p3,\n                            RegDataType::Single(ColumnType::Single {\n                                datatype: DataType::Integer,\n                                nullable: Some(false),\n                            }),\n                        );\n                    } else if p4.starts_with(\"percent_rank(\") || p4.starts_with(\"cume_dist\") {\n                        // percent_rank(_) -> REAL\n                        state.mem.r.insert(\n                            p3,\n                            RegDataType::Single(ColumnType::Single {\n                                datatype: DataType::Float,\n                                nullable: Some(false),\n                            }),\n                        );\n                    } else if p4.starts_with(\"sum(\") {\n                        if let Some(r_p2) = state.mem.r.get(&p2) {\n                            let datatype = match r_p2.map_to_datatype() {\n                                // The result of a `SUM()` can be arbitrarily large\n                                DataType::Integer | DataType::Int4 | DataType::Bool => {\n                                    DataType::Integer\n                                }\n                                _ => DataType::Float,\n                            };\n                            let nullable = r_p2.map_to_nullable();\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single { datatype, nullable }),\n                            );\n                        }\n                    } else if p4.starts_with(\"lead(\") || p4.starts_with(\"lag(\") {\n                        if let Some(r_p2) = state.mem.r.get(&p2) {\n                            let datatype = r_p2.map_to_datatype();\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype,\n                                    nullable: Some(true),\n                                }),\n                            );\n                        }\n                    } else if let Some(v) = state.mem.r.get(&p2).cloned() {\n                        // r[p3] = AGG ( r[p2] )\n                        state.mem.r.insert(p3, v);\n                    }\n                }\n\n                OP_AGG_FINAL => {\n                    let p4 = from_utf8(p4).map_err(Error::protocol)?;\n\n                    if p4.starts_with(\"count(\")\n                        || p4.starts_with(\"row_number(\")\n                        || p4.starts_with(\"rank(\")\n                        || p4.starts_with(\"dense_rank(\")\n                        || p4.starts_with(\"ntile(\")\n                    {\n                        // count(_) -> INTEGER\n                        state.mem.r.insert(\n                            p1,\n                            RegDataType::Single(ColumnType::Single {\n                                datatype: DataType::Integer,\n                                nullable: Some(false),\n                            }),\n                        );\n                    } else if p4.starts_with(\"percent_rank(\") || p4.starts_with(\"cume_dist\") {\n                        // percent_rank(_) -> REAL\n                        state.mem.r.insert(\n                            p3,\n                            RegDataType::Single(ColumnType::Single {\n                                datatype: DataType::Float,\n                                nullable: Some(false),\n                            }),\n                        );\n                    } else if p4.starts_with(\"lead(\") || p4.starts_with(\"lag(\") {\n                        if let Some(r_p2) = state.mem.r.get(&p2) {\n                            let datatype = r_p2.map_to_datatype();\n                            state.mem.r.insert(\n                                p3,\n                                RegDataType::Single(ColumnType::Single {\n                                    datatype,\n                                    nullable: Some(true),\n                                }),\n                            );\n                        }\n                    }\n                }\n\n                OP_CAST => {\n                    // affinity(r[p1])\n                    if let Some(v) = state.mem.r.get_mut(&p1) {\n                        *v = RegDataType::Single(ColumnType::Single {\n                            datatype: affinity_to_type(p2 as u8),\n                            nullable: v.map_to_nullable(),\n                        });\n                    }\n                }\n\n                OP_SCOPY | OP_INT_COPY => {\n                    // r[p2] = r[p1]\n                    if let Some(v) = state.mem.r.get(&p1).cloned() {\n                        state.mem.r.insert(p2, v);\n                    }\n                }\n\n                OP_COPY => {\n                    // r[p2..=p2+p3] = r[p1..=p1+p3]\n                    if p3 >= 0 {\n                        for i in 0..=p3 {\n                            let src = p1 + i;\n                            let dst = p2 + i;\n                            if let Some(v) = state.mem.r.get(&src).cloned() {\n                                state.mem.r.insert(dst, v);\n                            }\n                        }\n                    }\n                }\n\n                OP_MOVE => {\n                    // r[p2..p2+p3] = r[p1..p1+p3]; r[p1..p1+p3] = null\n                    if p3 >= 1 {\n                        for i in 0..p3 {\n                            let src = p1 + i;\n                            let dst = p2 + i;\n                            if let Some(v) = state.mem.r.get(&src).cloned() {\n                                state.mem.r.insert(dst, v);\n                                state\n                                    .mem\n                                    .r\n                                    .insert(src, RegDataType::Single(ColumnType::null()));\n                            }\n                        }\n                    }\n                }\n\n                OP_INTEGER => {\n                    // r[p2] = p1\n                    state.mem.r.insert(p2, RegDataType::Int(p1));\n                }\n\n                OP_BLOB | OP_COUNT | OP_REAL | OP_STRING8 | OP_ROWID | OP_NEWROWID => {\n                    // r[p2] = <value of constant>\n                    state.mem.r.insert(\n                        p2,\n                        RegDataType::Single(ColumnType::Single {\n                            datatype: opcode_to_type(opcode),\n                            nullable: Some(false),\n                        }),\n                    );\n                }\n\n                OP_NOT => {\n                    // r[p2] = NOT r[p1]\n                    if let Some(a) = state.mem.r.get(&p1).cloned() {\n                        state.mem.r.insert(p2, a);\n                    }\n                }\n\n                OP_NULL => {\n                    // r[p2..p3] = null\n                    let idx_range = if p2 < p3 { p2..=p3 } else { p2..=p2 };\n\n                    for idx in idx_range {\n                        state\n                            .mem\n                            .r\n                            .insert(idx, RegDataType::Single(ColumnType::null()));\n                    }\n                }\n\n                OP_OR | OP_AND | OP_BIT_AND | OP_BIT_OR | OP_SHIFT_LEFT | OP_SHIFT_RIGHT\n                | OP_ADD | OP_SUBTRACT | OP_MULTIPLY | OP_DIVIDE | OP_REMAINDER | OP_CONCAT => {\n                    // r[p3] = r[p1] + r[p2]\n                    let value = match (state.mem.r.get(&p1), state.mem.r.get(&p2)) {\n                        (Some(a), Some(b)) => RegDataType::Single(ColumnType::Single {\n                            datatype: if matches!(a.map_to_datatype(), DataType::Null) {\n                                b.map_to_datatype()\n                            } else {\n                                a.map_to_datatype()\n                            },\n                            nullable: match (a.map_to_nullable(), b.map_to_nullable()) {\n                                (Some(a_n), Some(b_n)) => Some(a_n | b_n),\n                                (Some(a_n), None) => Some(a_n),\n                                (None, Some(b_n)) => Some(b_n),\n                                (None, None) => None,\n                            },\n                        }),\n                        (Some(v), None) => RegDataType::Single(ColumnType::Single {\n                            datatype: v.map_to_datatype(),\n                            nullable: None,\n                        }),\n                        (None, Some(v)) => RegDataType::Single(ColumnType::Single {\n                            datatype: v.map_to_datatype(),\n                            nullable: None,\n                        }),\n                        _ => RegDataType::default(),\n                    };\n\n                    state.mem.r.insert(p3, value);\n                }\n\n                OP_OFFSET_LIMIT => {\n                    // r[p2] = if r[p2] < 0 { r[p1] } else if r[p1]<0 { -1 } else { r[p1] + r[p3] }\n                    state.mem.r.insert(\n                        p2,\n                        RegDataType::Single(ColumnType::Single {\n                            datatype: DataType::Integer,\n                            nullable: Some(false),\n                        }),\n                    );\n                }\n\n                OP_RESULT_ROW => {\n                    // output = r[p1 .. p1 + p2]\n                    let result: Vec<_> = (p1..p1 + p2)\n                        .map(|i| {\n                            state\n                                .mem\n                                .r\n                                .get(&i)\n                                .map(RegDataType::map_to_columntype)\n                                .unwrap_or_default()\n                        })\n                        .collect();\n\n                    let mut branch_state = state.new_branch(&mut branch_seq);\n                    branch_state.mem.program_i += 1;\n                    states.push(branch_state, &mut logger);\n\n                    logger.add_result(\n                        state,\n                        BranchResult::Result(IntMap::from_dense_record(&result)),\n                    );\n\n                    result_states.push(result);\n                    break;\n                }\n\n                OP_HALT => {\n                    logger.add_result(state, BranchResult::Halt);\n                    break;\n                }\n\n                _ => {\n                    // ignore unsupported operations\n                    // if we fail to find an r later, we just give up\n                    logger.add_unknown_operation(state.mem.program_i);\n                }\n            }\n\n            state.mem.program_i += 1;\n        }\n    }\n\n    let mut output: Vec<Option<SqliteTypeInfo>> = Vec::new();\n    let mut nullable: Vec<Option<bool>> = Vec::new();\n\n    while let Some(result) = result_states.pop() {\n        // find the datatype info from each ResultRow execution\n        for (idx, this_col) in result.into_iter().enumerate() {\n            let this_type = this_col.map_to_datatype();\n            let this_nullable = this_col.map_to_nullable();\n            if output.len() == idx {\n                output.push(Some(SqliteTypeInfo(this_type)));\n            } else if output[idx].is_none()\n                || matches!(output[idx], Some(SqliteTypeInfo(DataType::Null)))\n                    && !matches!(this_type, DataType::Null)\n            {\n                output[idx] = Some(SqliteTypeInfo(this_type));\n            }\n\n            if nullable.len() == idx {\n                nullable.push(this_nullable);\n            } else if let Some(ref mut null) = nullable[idx] {\n                //if any ResultRow's column is nullable, the final result is nullable\n                if let Some(this_null) = this_nullable {\n                    *null |= this_null;\n                }\n            } else {\n                nullable[idx] = this_nullable;\n            }\n        }\n    }\n\n    let output = output\n        .into_iter()\n        .map(|o| o.unwrap_or(SqliteTypeInfo(DataType::Null)))\n        .collect();\n\n    Ok((output, nullable))\n}\n\n#[test]\nfn test_root_block_columns_has_types() {\n    use crate::SqliteConnectOptions;\n    use std::str::FromStr;\n    let conn_options = SqliteConnectOptions::from_str(\"sqlite::memory:\").unwrap();\n    let mut conn = super::EstablishParams::from_options(&conn_options)\n        .unwrap()\n        .establish()\n        .unwrap();\n\n    assert!(execute::iter(\n        &mut conn,\n        r\"CREATE TABLE t(a INTEGER PRIMARY KEY, b_null TEXT NULL, b TEXT NOT NULL);\",\n        None,\n        false\n    )\n    .unwrap()\n    .next()\n    .is_some());\n    assert!(\n        execute::iter(&mut conn, r\"CREATE INDEX i1 on t (a,b_null);\", None, false)\n            .unwrap()\n            .next()\n            .is_some()\n    );\n    assert!(execute::iter(\n        &mut conn,\n        r\"CREATE UNIQUE INDEX i2 on t (a,b_null);\",\n        None,\n        false\n    )\n    .unwrap()\n    .next()\n    .is_some());\n    assert!(execute::iter(\n        &mut conn,\n        r\"CREATE TABLE t2(a INTEGER NOT NULL, b_null NUMERIC NULL, b NUMERIC NOT NULL);\",\n        None,\n        false\n    )\n    .unwrap()\n    .next()\n    .is_some());\n    assert!(execute::iter(\n        &mut conn,\n        r\"CREATE INDEX t2i1 on t2 (a,b_null);\",\n        None,\n        false\n    )\n    .unwrap()\n    .next()\n    .is_some());\n    assert!(execute::iter(\n        &mut conn,\n        r\"CREATE UNIQUE INDEX t2i2 on t2 (a,b);\",\n        None,\n        false\n    )\n    .unwrap()\n    .next()\n    .is_some());\n\n    assert!(execute::iter(\n        &mut conn,\n        r\"CREATE TEMPORARY TABLE t3(a TEXT PRIMARY KEY, b REAL NOT NULL, b_null REAL NULL);\",\n        None,\n        false\n    )\n    .unwrap()\n    .next()\n    .is_some());\n\n    let table_block_nums: HashMap<String, (i64,i64)> = execute::iter(\n        &mut conn,\n        r\"select name, 0 db_seq, rootpage from main.sqlite_schema UNION ALL select name, 1 db_seq, rootpage from temp.sqlite_schema\",\n        None,\n        false,\n    )\n    .unwrap()\n    .filter_map(|res| res.map(|either| either.right()).transpose())\n    .map(|row| FromRow::from_row(row.as_ref().unwrap()))\n    .map(|row| row.map(|(name,seq,block)|(name,(seq,block))))\n    .collect::<Result<HashMap<_, _>, Error>>()\n    .unwrap();\n\n    let root_block_cols = root_block_columns(&mut conn).unwrap();\n\n    // there should be 7 tables/indexes created explicitly, plus 1 autoindex for t3\n    assert_eq!(8, root_block_cols.len());\n\n    //prove that we have some information for each table & index\n    for (name, db_seq_block) in dbg!(&table_block_nums) {\n        assert!(\n            root_block_cols.contains_key(db_seq_block),\n            \"{:?}\",\n            (name, db_seq_block)\n        );\n    }\n\n    //prove that each block has the correct information\n    {\n        let table_db_block = table_block_nums[\"t\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(true) //sqlite primary key columns are nullable unless declared not null\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Text,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Text,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&2)\n        );\n    }\n\n    {\n        let table_db_block = table_block_nums[\"i1\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(true) //sqlite primary key columns are nullable unless declared not null\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Text,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n    }\n\n    {\n        let table_db_block = table_block_nums[\"i2\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(true) //sqlite primary key columns are nullable unless declared not null\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Text,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n    }\n\n    {\n        let table_db_block = table_block_nums[\"t2\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Null,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Null,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&2)\n        );\n    }\n\n    {\n        let table_db_block = table_block_nums[\"t2i1\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Null,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n    }\n\n    {\n        let table_db_block = table_block_nums[\"t2i2\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Integer,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Null,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n    }\n\n    {\n        let table_db_block = table_block_nums[\"t3\"];\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Text,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&0)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Float,\n                nullable: Some(false)\n            }),\n            root_block_cols[&table_db_block].get(&1)\n        );\n        assert_eq!(\n            Some(&ColumnType::Single {\n                datatype: DataType::Float,\n                nullable: Some(true)\n            }),\n            root_block_cols[&table_db_block].get(&2)\n        );\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/handle.rs",
    "content": "use std::ffi::{c_int, CStr, CString};\nuse std::ptr::NonNull;\nuse std::{io, ptr};\n\nuse crate::error::Error;\nuse libsqlite3_sys::{\n    sqlite3, sqlite3_close, sqlite3_exec, sqlite3_extended_result_codes, sqlite3_get_autocommit,\n    sqlite3_last_insert_rowid, sqlite3_open_v2, SQLITE_OK,\n};\n\nuse crate::SqliteError;\n\n/// Managed SQLite3 database handle.\n/// The database handle will be closed when this is dropped.\n#[derive(Debug)]\npub(crate) struct ConnectionHandle(NonNull<sqlite3>);\n\n// A SQLite3 handle is safe to send between threads, provided not more than\n// one is accessing it at the same time. This is upheld as long as [SQLITE_CONFIG_MULTITHREAD] is\n// enabled and [SQLITE_THREADSAFE] was enabled when sqlite was compiled. We refuse to work\n// if these conditions are not upheld.\n//\n// <https://www.sqlite.org/c3ref/threadsafe.html>\n// <https://www.sqlite.org/c3ref/c_config_covering_index_scan.html#sqliteconfigmultithread>\n\nunsafe impl Send for ConnectionHandle {}\n\nimpl ConnectionHandle {\n    pub(crate) fn open(filename: &CStr, flags: c_int) -> Result<Self, Error> {\n        let mut handle = ptr::null_mut();\n\n        // <https://www.sqlite.org/c3ref/open.html>\n        let status = unsafe { sqlite3_open_v2(filename.as_ptr(), &mut handle, flags, ptr::null()) };\n\n        // SAFETY: the database is still initialized as long as the pointer is not `NULL`.\n        // We need to close it even if there's an error.\n        let mut handle = Self(NonNull::new(handle).ok_or_else(|| {\n            Error::Io(io::Error::new(\n                io::ErrorKind::OutOfMemory,\n                \"SQLite is unable to allocate memory to hold the sqlite3 object\",\n            ))\n        })?);\n\n        if status != SQLITE_OK {\n            return Err(Error::Database(Box::new(handle.expect_error())));\n        }\n\n        // Enable extended result codes\n        // https://www.sqlite.org/c3ref/extended_result_codes.html\n        unsafe {\n            // This only returns a non-OK code if SQLite is built with `SQLITE_ENABLE_API_ARMOR`\n            // and the database pointer is `NULL` or already closed.\n            //\n            // The invariants of this type guarantee that neither is true.\n            sqlite3_extended_result_codes(handle.as_ptr(), 1);\n        }\n\n        Ok(handle)\n    }\n\n    #[inline]\n    pub(crate) fn as_ptr(&self) -> *mut sqlite3 {\n        self.0.as_ptr()\n    }\n\n    pub(crate) fn as_non_null_ptr(&self) -> NonNull<sqlite3> {\n        self.0\n    }\n\n    pub(crate) fn call_with_result(\n        &mut self,\n        call: impl FnOnce(*mut sqlite3) -> c_int,\n    ) -> Result<(), SqliteError> {\n        if call(self.as_ptr()) == SQLITE_OK {\n            Ok(())\n        } else {\n            Err(self.expect_error())\n        }\n    }\n\n    pub(crate) fn in_transaction(&mut self) -> bool {\n        // SAFETY: we have exclusive access to the database handle\n        let ret = unsafe { sqlite3_get_autocommit(self.as_ptr()) };\n        ret == 0\n    }\n\n    pub(crate) fn last_insert_rowid(&mut self) -> i64 {\n        // SAFETY: we have exclusive access to the database handle\n        unsafe { sqlite3_last_insert_rowid(self.as_ptr()) }\n    }\n\n    pub(crate) fn last_error(&mut self) -> Option<SqliteError> {\n        // SAFETY: we have exclusive access to the database handle\n        unsafe { SqliteError::try_new(self.as_ptr()) }\n    }\n\n    #[track_caller]\n    pub(crate) fn expect_error(&mut self) -> SqliteError {\n        self.last_error()\n            .expect(\"expected error code to be set in current context\")\n    }\n\n    pub(crate) fn exec(&mut self, query: impl Into<String>) -> Result<(), Error> {\n        let query = query.into();\n        let query = CString::new(query).map_err(|_| err_protocol!(\"query contains nul bytes\"))?;\n\n        // SAFETY: we have exclusive access to the database handle\n        unsafe {\n            #[cfg_attr(not(feature = \"unlock-notify\"), expect(clippy::never_loop))]\n            loop {\n                let status = sqlite3_exec(\n                    self.as_ptr(),\n                    query.as_ptr(),\n                    // callback if we wanted result rows\n                    None,\n                    // callback data\n                    ptr::null_mut(),\n                    // out-pointer for the error message, we just use `SqliteError::new()`\n                    ptr::null_mut(),\n                );\n\n                match status {\n                    SQLITE_OK => return Ok(()),\n                    #[cfg(feature = \"unlock-notify\")]\n                    libsqlite3_sys::SQLITE_LOCKED_SHAREDCACHE => {\n                        crate::statement::unlock_notify::wait(self.as_ptr())?\n                    }\n                    _ => return Err(SqliteError::new(self.as_ptr()).into()),\n                }\n            }\n        }\n    }\n}\n\nimpl Drop for ConnectionHandle {\n    fn drop(&mut self) {\n        unsafe {\n            // https://sqlite.org/c3ref/close.html\n            let status = sqlite3_close(self.0.as_ptr());\n            if status != SQLITE_OK {\n                // this should *only* happen due to an internal bug in SQLite where we left\n                // SQLite handles open\n                panic!(\"{}\", SqliteError::new(self.0.as_ptr()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/intmap.rs",
    "content": "// Bad casts in this module SHOULD NOT result in a SQL injection\n// https://github.com/launchbadge/sqlx/issues/3440\n#![allow(\n    clippy::cast_possible_truncation,\n    clippy::cast_possible_wrap,\n    clippy::cast_sign_loss\n)]\nuse std::cmp::Ordering;\nuse std::{fmt::Debug, hash::Hash};\n\n/// Simplistic map implementation built on a Vec of Options (index = key)\n#[derive(Debug, Clone, Eq)]\npub(crate) struct IntMap<V>(Vec<Option<V>>);\n\nimpl<V> Default for IntMap<V> {\n    fn default() -> Self {\n        IntMap(Vec::new())\n    }\n}\n\nimpl<V> IntMap<V> {\n    pub(crate) fn new() -> Self {\n        Self(Vec::new())\n    }\n\n    pub(crate) fn expand(&mut self, size: i64) -> usize {\n        let idx = usize::try_from(size).expect(\"negative column index unsupported\");\n        if idx >= self.0.len() {\n            let new_len = idx.checked_add(1).expect(\"idx + 1 overflowed\");\n\n            self.0.resize_with(new_len, || None);\n        }\n        idx\n    }\n\n    pub(crate) fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {\n        self.0.iter_mut().filter_map(Option::as_mut)\n    }\n\n    pub(crate) fn values(&self) -> impl Iterator<Item = &V> {\n        self.0.iter().filter_map(Option::as_ref)\n    }\n\n    pub(crate) fn get(&self, idx: &i64) -> Option<&V> {\n        let idx: usize = (*idx)\n            .try_into()\n            .expect(\"negative column index unsupported\");\n\n        match self.0.get(idx) {\n            Some(Some(v)) => Some(v),\n            _ => None,\n        }\n    }\n\n    pub(crate) fn get_mut(&mut self, idx: &i64) -> Option<&mut V> {\n        let idx: usize = (*idx)\n            .try_into()\n            .expect(\"negative column index unsupported\");\n        match self.0.get_mut(idx) {\n            Some(Some(v)) => Some(v),\n            _ => None,\n        }\n    }\n\n    pub(crate) fn insert(&mut self, idx: i64, value: V) -> Option<V> {\n        let idx: usize = self.expand(idx);\n\n        std::mem::replace(&mut self.0[idx], Some(value))\n    }\n\n    pub(crate) fn remove(&mut self, idx: &i64) -> Option<V> {\n        let idx: usize = (*idx)\n            .try_into()\n            .expect(\"negative column index unsupported\");\n\n        let item = self.0.get_mut(idx);\n        match item {\n            Some(content) => content.take(),\n            None => None,\n        }\n    }\n\n    pub(crate) fn iter(&self) -> impl Iterator<Item = Option<&V>> {\n        self.0.iter().map(Option::as_ref)\n    }\n\n    pub(crate) fn iter_entries(&self) -> impl Iterator<Item = (i64, &V)> {\n        self.0\n            .iter()\n            .enumerate()\n            .filter_map(|(i, v)| v.as_ref().map(|v: &V| (i as i64, v)))\n    }\n\n    pub(crate) fn last_index(&self) -> Option<i64> {\n        self.0.iter().rposition(|v| v.is_some()).map(|i| i as i64)\n    }\n}\n\nimpl<V: Default> IntMap<V> {\n    pub(crate) fn get_mut_or_default(&mut self, idx: &i64) -> &mut V {\n        let idx: usize = self.expand(*idx);\n        self.0[idx].get_or_insert_default()\n    }\n}\n\nimpl<V: Clone> IntMap<V> {\n    pub(crate) fn from_elem(elem: V, len: usize) -> Self {\n        Self(vec![Some(elem); len])\n    }\n    pub(crate) fn from_dense_record(record: &[V]) -> Self {\n        Self(record.iter().cloned().map(Some).collect())\n    }\n}\n\nimpl<V: Eq> IntMap<V> {\n    /// get the additions to this intmap compared to the prev intmap\n    pub(crate) fn diff<'a, 'b, 'c>(\n        &'a self,\n        prev: &'b Self,\n    ) -> impl Iterator<Item = (usize, Option<&'c V>)>\n    where\n        'a: 'c,\n        'b: 'c,\n    {\n        let self_pad = if prev.0.len() > self.0.len() {\n            prev.0.len() - self.0.len()\n        } else {\n            0\n        };\n        self.iter()\n            .chain(std::iter::repeat_n(None, self_pad))\n            .zip(prev.iter().chain(std::iter::repeat(None)))\n            .enumerate()\n            .filter(|(_i, (n, p))| n != p)\n            .map(|(i, (n, _p))| (i, n))\n    }\n}\n\nimpl<V: Hash> Hash for IntMap<V> {\n    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {\n        for value in self.values() {\n            value.hash(state);\n        }\n    }\n}\n\nimpl<V: PartialEq> PartialEq for IntMap<V> {\n    fn eq(&self, other: &Self) -> bool {\n        match self.0.len().cmp(&other.0.len()) {\n            Ordering::Greater => {\n                self.0[..other.0.len()] == other.0\n                    && self.0[other.0.len()..].iter().all(Option::is_none)\n            }\n            Ordering::Less => {\n                other.0[..self.0.len()] == self.0\n                    && other.0[self.0.len()..].iter().all(Option::is_none)\n            }\n            Ordering::Equal => self.0 == other.0,\n        }\n    }\n}\n\nimpl<V: Debug> FromIterator<(i64, V)> for IntMap<V> {\n    fn from_iter<I>(iter: I) -> Self\n    where\n        I: IntoIterator<Item = (i64, V)>,\n    {\n        let mut result = Self(Vec::new());\n        for (idx, val) in iter {\n            let idx = result.expand(idx);\n            result.0[idx] = Some(val);\n        }\n        result\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/mod.rs",
    "content": "use std::cmp::Ordering;\nuse std::ffi::CStr;\nuse std::fmt::Write;\nuse std::fmt::{self, Debug, Formatter};\nuse std::future::Future;\nuse std::os::raw::{c_char, c_int, c_void};\nuse std::panic::catch_unwind;\nuse std::ptr;\nuse std::ptr::NonNull;\n\nuse futures_intrusive::sync::MutexGuard;\nuse libsqlite3_sys::{\n    sqlite3, sqlite3_commit_hook, sqlite3_progress_handler, sqlite3_rollback_hook,\n    sqlite3_update_hook, SQLITE_DELETE, SQLITE_INSERT, SQLITE_UPDATE,\n};\n#[cfg(feature = \"preupdate-hook\")]\npub use preupdate_hook::*;\n\npub(crate) use handle::ConnectionHandle;\nuse sqlx_core::common::StatementCache;\npub(crate) use sqlx_core::connection::*;\nuse sqlx_core::error::Error;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::sql_str::{AssertSqlSafe, SqlSafeStr};\nuse sqlx_core::transaction::Transaction;\n\nuse crate::connection::establish::EstablishParams;\nuse crate::connection::worker::ConnectionWorker;\nuse crate::options::OptimizeOnClose;\nuse crate::statement::VirtualStatement;\nuse crate::{Sqlite, SqliteConnectOptions, SqliteError};\n\npub(crate) mod collation;\npub(crate) mod describe;\npub(crate) mod establish;\npub(crate) mod execute;\nmod executor;\nmod explain;\nmod handle;\npub(crate) mod intmap;\n#[cfg(feature = \"preupdate-hook\")]\nmod preupdate_hook;\n\n#[cfg(feature = \"deserialize\")]\npub(crate) mod deserialize;\n\nmod worker;\n\n/// A connection to an open [Sqlite] database.\n///\n/// Because SQLite is an in-process database accessed by blocking API calls, SQLx uses a background\n/// thread and communicates with it via channels to allow non-blocking access to the database.\n///\n/// Dropping this struct will signal the worker thread to quit and close the database, though\n/// if an error occurs there is no way to pass it back to the user this way.\n///\n/// You can explicitly call [`.close()`][Self::close] to ensure the database is closed successfully\n/// or get an error otherwise.\npub struct SqliteConnection {\n    optimize_on_close: OptimizeOnClose,\n    pub(crate) worker: ConnectionWorker,\n    pub(crate) row_channel_size: usize,\n}\n\npub struct LockedSqliteHandle<'a> {\n    pub(crate) guard: MutexGuard<'a, ConnectionState>,\n}\n\n/// Represents a callback handler that will be shared with the underlying sqlite3 connection.\npub(crate) struct Handler(NonNull<dyn FnMut() -> bool + Send + 'static>);\nunsafe impl Send for Handler {}\n\n#[derive(Debug, PartialEq, Eq, Clone)]\npub enum SqliteOperation {\n    Insert,\n    Update,\n    Delete,\n    Unknown(i32),\n}\n\nimpl From<i32> for SqliteOperation {\n    fn from(value: i32) -> Self {\n        match value {\n            SQLITE_INSERT => SqliteOperation::Insert,\n            SQLITE_UPDATE => SqliteOperation::Update,\n            SQLITE_DELETE => SqliteOperation::Delete,\n            code => SqliteOperation::Unknown(code),\n        }\n    }\n}\n\npub struct UpdateHookResult<'a> {\n    pub operation: SqliteOperation,\n    pub database: &'a str,\n    pub table: &'a str,\n    pub rowid: i64,\n}\n\npub(crate) struct UpdateHookHandler(NonNull<dyn FnMut(UpdateHookResult) + Send + 'static>);\nunsafe impl Send for UpdateHookHandler {}\n\npub(crate) struct CommitHookHandler(NonNull<dyn FnMut() -> bool + Send + 'static>);\nunsafe impl Send for CommitHookHandler {}\n\npub(crate) struct RollbackHookHandler(NonNull<dyn FnMut() + Send + 'static>);\nunsafe impl Send for RollbackHookHandler {}\n\npub(crate) struct ConnectionState {\n    pub(crate) handle: ConnectionHandle,\n\n    pub(crate) statements: Statements,\n\n    log_settings: LogSettings,\n\n    /// Stores the progress handler set on the current connection. If the handler returns `false`,\n    /// the query is interrupted.\n    progress_handler_callback: Option<Handler>,\n\n    update_hook_callback: Option<UpdateHookHandler>,\n    #[cfg(feature = \"preupdate-hook\")]\n    preupdate_hook_callback: Option<preupdate_hook::PreupdateHookHandler>,\n\n    commit_hook_callback: Option<CommitHookHandler>,\n\n    rollback_hook_callback: Option<RollbackHookHandler>,\n}\n\nimpl ConnectionState {\n    /// Drops the `progress_handler_callback` if it exists.\n    pub(crate) fn remove_progress_handler(&mut self) {\n        if let Some(mut handler) = self.progress_handler_callback.take() {\n            unsafe {\n                sqlite3_progress_handler(self.handle.as_ptr(), 0, None, ptr::null_mut());\n                let _ = { Box::from_raw(handler.0.as_mut()) };\n            }\n        }\n    }\n\n    pub(crate) fn remove_update_hook(&mut self) {\n        if let Some(mut handler) = self.update_hook_callback.take() {\n            unsafe {\n                sqlite3_update_hook(self.handle.as_ptr(), None, ptr::null_mut());\n                let _ = { Box::from_raw(handler.0.as_mut()) };\n            }\n        }\n    }\n\n    #[cfg(feature = \"preupdate-hook\")]\n    pub(crate) fn remove_preupdate_hook(&mut self) {\n        if let Some(mut handler) = self.preupdate_hook_callback.take() {\n            unsafe {\n                libsqlite3_sys::sqlite3_preupdate_hook(self.handle.as_ptr(), None, ptr::null_mut());\n                let _ = { Box::from_raw(handler.0.as_mut()) };\n            }\n        }\n    }\n\n    pub(crate) fn remove_commit_hook(&mut self) {\n        if let Some(mut handler) = self.commit_hook_callback.take() {\n            unsafe {\n                sqlite3_commit_hook(self.handle.as_ptr(), None, ptr::null_mut());\n                let _ = { Box::from_raw(handler.0.as_mut()) };\n            }\n        }\n    }\n\n    pub(crate) fn remove_rollback_hook(&mut self) {\n        if let Some(mut handler) = self.rollback_hook_callback.take() {\n            unsafe {\n                sqlite3_rollback_hook(self.handle.as_ptr(), None, ptr::null_mut());\n                let _ = { Box::from_raw(handler.0.as_mut()) };\n            }\n        }\n    }\n}\n\npub(crate) struct Statements {\n    // cache of semi-persistent statements\n    cached: StatementCache<VirtualStatement>,\n    // most recent non-persistent statement\n    temp: Option<VirtualStatement>,\n}\n\nimpl SqliteConnection {\n    pub(crate) async fn establish(options: &SqliteConnectOptions) -> Result<Self, Error> {\n        let params = EstablishParams::from_options(options)?;\n        let worker = ConnectionWorker::establish(params).await?;\n        Ok(Self {\n            optimize_on_close: options.optimize_on_close.clone(),\n            worker,\n            row_channel_size: options.row_channel_size,\n        })\n    }\n\n    /// Lock the SQLite database handle out from the worker thread so direct SQLite API calls can\n    /// be made safely.\n    ///\n    /// Returns an error if the worker thread crashed.\n    pub async fn lock_handle(&mut self) -> Result<LockedSqliteHandle<'_>, Error> {\n        let guard = self.worker.unlock_db().await?;\n\n        Ok(LockedSqliteHandle { guard })\n    }\n}\n\nimpl Debug for SqliteConnection {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.debug_struct(\"SqliteConnection\")\n            .field(\"row_channel_size\", &self.row_channel_size)\n            .field(\"cached_statements_size\", &self.cached_statements_size())\n            .finish()\n    }\n}\n\nimpl Connection for SqliteConnection {\n    type Database = Sqlite;\n\n    type Options = SqliteConnectOptions;\n\n    async fn close(mut self) -> Result<(), Error> {\n        if let OptimizeOnClose::Enabled { analysis_limit } = self.optimize_on_close {\n            let mut pragma_string = String::new();\n            if let Some(limit) = analysis_limit {\n                write!(pragma_string, \"PRAGMA analysis_limit = {limit}; \").ok();\n            }\n            pragma_string.push_str(\"PRAGMA optimize;\");\n            self.execute(AssertSqlSafe(pragma_string)).await?;\n        }\n        let shutdown = self.worker.shutdown();\n        // Drop the statement worker, which should\n        // cover all references to the connection handle outside of the worker thread\n        drop(self);\n        // Ensure the worker thread has terminated\n        shutdown.await\n    }\n\n    async fn close_hard(self) -> Result<(), Error> {\n        drop(self);\n        Ok(())\n    }\n\n    /// Ensure the background worker thread is alive and accepting commands.\n    fn ping(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        self.worker.ping()\n    }\n\n    fn begin(\n        &mut self,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_ {\n        Transaction::begin(self, None)\n    }\n\n    fn begin_with(\n        &mut self,\n        statement: impl SqlSafeStr,\n    ) -> impl Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_\n    where\n        Self: Sized,\n    {\n        Transaction::begin(self, Some(statement.into_sql_str()))\n    }\n\n    fn cached_statements_size(&self) -> usize {\n        self.worker.shared.get_cached_statements_size()\n    }\n\n    fn clear_cached_statements(&mut self) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        self.worker.clear_cache()\n    }\n\n    #[inline]\n    fn shrink_buffers(&mut self) {\n        // No-op.\n    }\n\n    #[doc(hidden)]\n    async fn flush(&mut self) -> Result<(), Error> {\n        // For SQLite, FLUSH does effectively nothing...\n        // Well, we could use this to ensure that the command channel has been cleared,\n        // but it would only develop a backlog if a lot of queries are executed and then cancelled\n        // partway through, and then this would only make that situation worse.\n        Ok(())\n    }\n\n    #[doc(hidden)]\n    fn should_flush(&self) -> bool {\n        false\n    }\n}\n\n/// Implements a C binding to a progress callback. The function returns `0` if the\n/// user-provided callback returns `true`, and `1` otherwise to signal an interrupt.\nextern \"C\" fn progress_callback<F>(callback: *mut c_void) -> c_int\nwhere\n    F: FnMut() -> bool,\n{\n    unsafe {\n        let r = catch_unwind(|| {\n            let callback: *mut F = callback.cast::<F>();\n            (*callback)()\n        });\n        c_int::from(!r.unwrap_or_default())\n    }\n}\n\nextern \"C\" fn update_hook<F>(\n    callback: *mut c_void,\n    op_code: c_int,\n    database: *const c_char,\n    table: *const c_char,\n    rowid: i64,\n) where\n    F: FnMut(UpdateHookResult),\n{\n    unsafe {\n        let _ = catch_unwind(|| {\n            let callback: *mut F = callback.cast::<F>();\n            let operation: SqliteOperation = op_code.into();\n            let database = CStr::from_ptr(database).to_str().unwrap_or_default();\n            let table = CStr::from_ptr(table).to_str().unwrap_or_default();\n            (*callback)(UpdateHookResult {\n                operation,\n                database,\n                table,\n                rowid,\n            })\n        });\n    }\n}\n\nextern \"C\" fn commit_hook<F>(callback: *mut c_void) -> c_int\nwhere\n    F: FnMut() -> bool,\n{\n    unsafe {\n        let r = catch_unwind(|| {\n            let callback: *mut F = callback.cast::<F>();\n            (*callback)()\n        });\n        c_int::from(!r.unwrap_or_default())\n    }\n}\n\nextern \"C\" fn rollback_hook<F>(callback: *mut c_void)\nwhere\n    F: FnMut(),\n{\n    unsafe {\n        let _ = catch_unwind(|| {\n            let callback: *mut F = callback.cast::<F>();\n            (*callback)()\n        });\n    }\n}\n\nimpl LockedSqliteHandle<'_> {\n    /// Returns the underlying sqlite3* connection handle.\n    ///\n    /// As long as this `LockedSqliteHandle` exists, it is guaranteed that the background thread\n    /// is not making FFI calls on this database handle or any of its statements.\n    ///\n    /// ### Note: The `sqlite3` type is semver-exempt.\n    /// This API exposes the `sqlite3` type from `libsqlite3-sys` crate for type safety.\n    /// However, we reserve the right to upgrade `libsqlite3-sys` as necessary.\n    ///\n    /// Thus, if you are making direct calls via `libsqlite3-sys` you should pin the version\n    /// of SQLx that you're using, and upgrade it and `libsqlite3-sys` manually as new\n    /// versions are released.\n    ///\n    /// See [the driver root docs][crate] for details.\n    pub fn as_raw_handle(&mut self) -> NonNull<sqlite3> {\n        self.guard.handle.as_non_null_ptr()\n    }\n\n    /// Apply a collation to the open database.\n    ///\n    /// See [`SqliteConnectOptions::collation()`] for details.\n    pub fn create_collation(\n        &mut self,\n        name: &str,\n        compare: impl Fn(&str, &str) -> Ordering + Send + Sync + 'static,\n    ) -> Result<(), Error> {\n        collation::create_collation(&mut self.guard.handle, name, compare)\n    }\n\n    /// Sets a progress handler that is invoked periodically during long running calls. If the progress callback\n    /// returns `false`, then the operation is interrupted.\n    ///\n    /// `num_ops` is the approximate number of [virtual machine instructions](https://www.sqlite.org/opcode.html)\n    /// that are evaluated between successive invocations of the callback. If `num_ops` is less than one then the\n    /// progress handler is disabled.\n    ///\n    /// Only a single progress handler may be defined at one time per database connection; setting a new progress\n    /// handler cancels the old one.\n    ///\n    /// The progress handler callback must not do anything that will modify the database connection that invoked\n    /// the progress handler. Note that sqlite3_prepare_v2() and sqlite3_step() both modify their database connections\n    /// in this context.\n    pub fn set_progress_handler<F>(&mut self, num_ops: i32, callback: F)\n    where\n        F: FnMut() -> bool + Send + 'static,\n    {\n        unsafe {\n            let callback_boxed = Box::new(callback);\n            // SAFETY: `Box::into_raw()` always returns a non-null pointer.\n            let callback = NonNull::new_unchecked(Box::into_raw(callback_boxed));\n            let handler = callback.as_ptr() as *mut _;\n            self.guard.remove_progress_handler();\n            self.guard.progress_handler_callback = Some(Handler(callback));\n\n            sqlite3_progress_handler(\n                self.as_raw_handle().as_mut(),\n                num_ops,\n                Some(progress_callback::<F>),\n                handler,\n            );\n        }\n    }\n\n    pub fn set_update_hook<F>(&mut self, callback: F)\n    where\n        F: FnMut(UpdateHookResult) + Send + 'static,\n    {\n        unsafe {\n            let callback_boxed = Box::new(callback);\n            // SAFETY: `Box::into_raw()` always returns a non-null pointer.\n            let callback = NonNull::new_unchecked(Box::into_raw(callback_boxed));\n            let handler = callback.as_ptr() as *mut _;\n            self.guard.remove_update_hook();\n            self.guard.update_hook_callback = Some(UpdateHookHandler(callback));\n\n            sqlite3_update_hook(\n                self.as_raw_handle().as_mut(),\n                Some(update_hook::<F>),\n                handler,\n            );\n        }\n    }\n\n    /// Registers a hook that is invoked prior to each `INSERT`, `UPDATE`, and `DELETE` operation on a database table.\n    /// At most one preupdate hook may be registered at a time on a single database connection.\n    ///\n    /// The preupdate hook only fires for changes to real database tables;\n    /// it is not invoked for changes to virtual tables or to system tables like sqlite_sequence or sqlite_stat1.\n    ///\n    /// See https://sqlite.org/c3ref/preupdate_count.html\n    #[cfg(feature = \"preupdate-hook\")]\n    pub fn set_preupdate_hook<F>(&mut self, callback: F)\n    where\n        F: FnMut(PreupdateHookResult) + Send + 'static,\n    {\n        unsafe {\n            let callback_boxed = Box::new(callback);\n            // SAFETY: `Box::into_raw()` always returns a non-null pointer.\n            let callback = NonNull::new_unchecked(Box::into_raw(callback_boxed));\n            let handler = callback.as_ptr() as *mut _;\n            self.guard.remove_preupdate_hook();\n            self.guard.preupdate_hook_callback = Some(PreupdateHookHandler(callback));\n\n            libsqlite3_sys::sqlite3_preupdate_hook(\n                self.as_raw_handle().as_mut(),\n                Some(preupdate_hook::<F>),\n                handler,\n            );\n        }\n    }\n\n    /// Sets a commit hook that is invoked whenever a transaction is committed. If the commit hook callback\n    /// returns `false`, then the operation is turned into a ROLLBACK.\n    ///\n    /// Only a single commit hook may be defined at one time per database connection; setting a new commit hook\n    /// overrides the old one.\n    ///\n    /// The commit hook callback must not do anything that will modify the database connection that invoked\n    /// the commit hook. Note that sqlite3_prepare_v2() and sqlite3_step() both modify their database connections\n    /// in this context.\n    ///\n    /// See https://www.sqlite.org/c3ref/commit_hook.html\n    pub fn set_commit_hook<F>(&mut self, callback: F)\n    where\n        F: FnMut() -> bool + Send + 'static,\n    {\n        unsafe {\n            let callback_boxed = Box::new(callback);\n            // SAFETY: `Box::into_raw()` always returns a non-null pointer.\n            let callback = NonNull::new_unchecked(Box::into_raw(callback_boxed));\n            let handler = callback.as_ptr() as *mut _;\n            self.guard.remove_commit_hook();\n            self.guard.commit_hook_callback = Some(CommitHookHandler(callback));\n\n            sqlite3_commit_hook(\n                self.as_raw_handle().as_mut(),\n                Some(commit_hook::<F>),\n                handler,\n            );\n        }\n    }\n\n    /// Sets a rollback hook that is invoked whenever a transaction rollback occurs. The rollback callback is not\n    /// invoked if a transaction is automatically rolled back because the database connection is closed.\n    ///\n    /// See https://www.sqlite.org/c3ref/commit_hook.html\n    pub fn set_rollback_hook<F>(&mut self, callback: F)\n    where\n        F: FnMut() + Send + 'static,\n    {\n        unsafe {\n            let callback_boxed = Box::new(callback);\n            // SAFETY: `Box::into_raw()` always returns a non-null pointer.\n            let callback = NonNull::new_unchecked(Box::into_raw(callback_boxed));\n            let handler = callback.as_ptr() as *mut _;\n            self.guard.remove_rollback_hook();\n            self.guard.rollback_hook_callback = Some(RollbackHookHandler(callback));\n\n            sqlite3_rollback_hook(\n                self.as_raw_handle().as_mut(),\n                Some(rollback_hook::<F>),\n                handler,\n            );\n        }\n    }\n\n    /// Removes the progress handler on a database connection. The method does nothing if no handler was set.\n    pub fn remove_progress_handler(&mut self) {\n        self.guard.remove_progress_handler();\n    }\n\n    pub fn remove_update_hook(&mut self) {\n        self.guard.remove_update_hook();\n    }\n\n    #[cfg(feature = \"preupdate-hook\")]\n    pub fn remove_preupdate_hook(&mut self) {\n        self.guard.remove_preupdate_hook();\n    }\n\n    pub fn remove_commit_hook(&mut self) {\n        self.guard.remove_commit_hook();\n    }\n\n    pub fn remove_rollback_hook(&mut self) {\n        self.guard.remove_rollback_hook();\n    }\n\n    pub fn last_error(&mut self) -> Option<SqliteError> {\n        self.guard.handle.last_error()\n    }\n}\n\nimpl Drop for ConnectionState {\n    fn drop(&mut self) {\n        // explicitly drop statements before the connection handle is dropped\n        self.statements.clear();\n        self.remove_progress_handler();\n        self.remove_update_hook();\n        self.remove_commit_hook();\n        self.remove_rollback_hook();\n    }\n}\n\nimpl Statements {\n    fn new(capacity: usize) -> Self {\n        Statements {\n            cached: StatementCache::new(capacity),\n            temp: None,\n        }\n    }\n\n    fn get(&mut self, query: &str, persistent: bool) -> Result<&mut VirtualStatement, Error> {\n        if !persistent || !self.cached.is_enabled() {\n            return Ok(self.temp.insert(VirtualStatement::new(query, false)?));\n        }\n\n        let exists = self.cached.contains_key(query);\n\n        if !exists {\n            let statement = VirtualStatement::new(query, true)?;\n            self.cached.insert(query, statement);\n        }\n\n        let statement = self.cached.get_mut(query).unwrap();\n\n        if exists {\n            // as this statement has been executed before, we reset before continuing\n            statement.reset()?;\n        }\n\n        Ok(statement)\n    }\n\n    fn len(&self) -> usize {\n        self.cached.len()\n    }\n\n    fn clear(&mut self) {\n        self.cached.clear();\n        self.temp = None;\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/preupdate_hook.rs",
    "content": "use super::SqliteOperation;\nuse crate::{SqliteError, SqliteValueRef};\n\nuse libsqlite3_sys::{\n    sqlite3, sqlite3_preupdate_count, sqlite3_preupdate_depth, sqlite3_preupdate_new,\n    sqlite3_preupdate_old, sqlite3_value, SQLITE_OK,\n};\nuse std::ffi::CStr;\nuse std::marker::PhantomData;\nuse std::os::raw::{c_char, c_int, c_void};\nuse std::panic::catch_unwind;\nuse std::ptr;\nuse std::ptr::NonNull;\n\n#[derive(Debug, thiserror::Error)]\npub enum PreupdateError {\n    /// Error returned from the database.\n    #[error(\"error returned from database: {0}\")]\n    Database(#[source] SqliteError),\n    /// Index is not within the valid column range\n    #[error(\"{0} is not within the valid column range\")]\n    ColumnIndexOutOfBounds(i32),\n    /// Column value accessor was invoked from an invalid operation\n    #[error(\"column value accessor was invoked from an invalid operation\")]\n    InvalidOperation,\n}\n\npub(crate) struct PreupdateHookHandler(\n    pub(super) NonNull<dyn FnMut(PreupdateHookResult) + Send + 'static>,\n);\nunsafe impl Send for PreupdateHookHandler {}\n\n#[derive(Debug)]\npub struct PreupdateHookResult<'a> {\n    pub operation: SqliteOperation,\n    pub database: &'a str,\n    pub table: &'a str,\n    db: *mut sqlite3,\n    // The database pointer should not be usable after the preupdate hook.\n    // The lifetime on this struct needs to ensure it cannot outlive the callback.\n    _db_lifetime: PhantomData<&'a ()>,\n    old_row_id: i64,\n    new_row_id: i64,\n}\n\nimpl<'a> PreupdateHookResult<'a> {\n    /// Gets the amount of columns in the row being inserted, deleted, or updated.\n    pub fn get_column_count(&self) -> i32 {\n        unsafe { sqlite3_preupdate_count(self.db) }\n    }\n\n    /// Gets the depth of the query that triggered the preupdate hook.\n    /// Returns 0 if the preupdate callback was invoked as a result of\n    /// a direct insert, update, or delete operation;\n    /// 1 for inserts, updates, or deletes invoked by top-level triggers;\n    /// 2 for changes resulting from triggers called by top-level triggers; and so forth.\n    pub fn get_query_depth(&self) -> i32 {\n        unsafe { sqlite3_preupdate_depth(self.db) }\n    }\n\n    /// Gets the row id of the row being updated/deleted.\n    /// Returns an error if called from an insert operation.\n    pub fn get_old_row_id(&self) -> Result<i64, PreupdateError> {\n        if self.operation == SqliteOperation::Insert {\n            return Err(PreupdateError::InvalidOperation);\n        }\n        Ok(self.old_row_id)\n    }\n\n    /// Gets the row id of the row being inserted/updated.\n    /// Returns an error if called from a delete operation.\n    pub fn get_new_row_id(&self) -> Result<i64, PreupdateError> {\n        if self.operation == SqliteOperation::Delete {\n            return Err(PreupdateError::InvalidOperation);\n        }\n        Ok(self.new_row_id)\n    }\n\n    /// Gets the value of the row being updated/deleted at the specified index.\n    /// Returns an error if called from an insert operation or the index is out of bounds.\n    pub fn get_old_column_value(&self, i: i32) -> Result<SqliteValueRef<'a>, PreupdateError> {\n        if self.operation == SqliteOperation::Insert {\n            return Err(PreupdateError::InvalidOperation);\n        }\n        self.validate_column_index(i)?;\n\n        let mut p_value: *mut sqlite3_value = ptr::null_mut();\n        unsafe {\n            let ret = sqlite3_preupdate_old(self.db, i, &mut p_value);\n            self.get_value(ret, p_value)\n        }\n    }\n\n    /// Gets the value of the row being inserted/updated at the specified index.\n    /// Returns an error if called from a delete operation or the index is out of bounds.\n    pub fn get_new_column_value(&self, i: i32) -> Result<SqliteValueRef<'a>, PreupdateError> {\n        if self.operation == SqliteOperation::Delete {\n            return Err(PreupdateError::InvalidOperation);\n        }\n        self.validate_column_index(i)?;\n\n        let mut p_value: *mut sqlite3_value = ptr::null_mut();\n        unsafe {\n            let ret = sqlite3_preupdate_new(self.db, i, &mut p_value);\n            self.get_value(ret, p_value)\n        }\n    }\n\n    fn validate_column_index(&self, i: i32) -> Result<(), PreupdateError> {\n        if i < 0 || i >= self.get_column_count() {\n            return Err(PreupdateError::ColumnIndexOutOfBounds(i));\n        }\n        Ok(())\n    }\n\n    unsafe fn get_value(\n        &self,\n        ret: i32,\n        p_value: *mut sqlite3_value,\n    ) -> Result<SqliteValueRef<'a>, PreupdateError> {\n        if ret != SQLITE_OK {\n            return Err(PreupdateError::Database(SqliteError::new(self.db)));\n        }\n        Ok(SqliteValueRef::borrowed(p_value))\n    }\n}\n\npub(super) extern \"C\" fn preupdate_hook<F>(\n    callback: *mut c_void,\n    db: *mut sqlite3,\n    op_code: c_int,\n    database: *const c_char,\n    table: *const c_char,\n    old_row_id: i64,\n    new_row_id: i64,\n) where\n    F: FnMut(PreupdateHookResult) + Send + 'static,\n{\n    unsafe {\n        let _ = catch_unwind(|| {\n            let callback: *mut F = callback.cast::<F>();\n            let operation: SqliteOperation = op_code.into();\n            let database = CStr::from_ptr(database).to_str().unwrap_or_default();\n            let table = CStr::from_ptr(table).to_str().unwrap_or_default();\n\n            (*callback)(PreupdateHookResult {\n                operation,\n                database,\n                table,\n                old_row_id,\n                new_row_id,\n                db,\n                _db_lifetime: PhantomData,\n            })\n        });\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/connection/worker.rs",
    "content": "use std::future::Future;\nuse std::sync::atomic::{AtomicUsize, Ordering};\nuse std::sync::Arc;\nuse std::thread;\n\nuse futures_channel::oneshot;\nuse futures_intrusive::sync::{Mutex, MutexGuard};\nuse sqlx_core::sql_str::SqlStr;\nuse tracing::span::Span;\n\nuse sqlx_core::error::Error;\nuse sqlx_core::transaction::{\n    begin_ansi_transaction_sql, commit_ansi_transaction_sql, rollback_ansi_transaction_sql,\n};\nuse sqlx_core::Either;\n\nuse crate::connection::establish::EstablishParams;\nuse crate::connection::execute;\nuse crate::connection::ConnectionState;\nuse crate::{SqliteArguments, SqliteQueryResult, SqliteRow, SqliteStatement};\n\n#[cfg(feature = \"deserialize\")]\nuse crate::connection::deserialize::{deserialize, serialize, SchemaName, SqliteOwnedBuf};\n\n// Each SQLite connection has a dedicated thread.\n\n// TODO: Tweak this so that we can use a thread pool per pool of SQLite3 connections to reduce\n//       OS resource usage. Low priority because a high concurrent load for SQLite3 is very\n//       unlikely.\n\npub(crate) struct ConnectionWorker {\n    command_tx: flume::Sender<(Command, tracing::Span)>,\n    /// Mutex for locking access to the database.\n    pub(crate) shared: Arc<WorkerSharedState>,\n}\n\npub(crate) struct WorkerSharedState {\n    transaction_depth: AtomicUsize,\n    cached_statements_size: AtomicUsize,\n    pub(crate) conn: Mutex<ConnectionState>,\n}\n\nimpl WorkerSharedState {\n    pub(crate) fn get_transaction_depth(&self) -> usize {\n        self.transaction_depth.load(Ordering::Acquire)\n    }\n\n    pub(crate) fn get_cached_statements_size(&self) -> usize {\n        self.cached_statements_size.load(Ordering::Acquire)\n    }\n}\n\nenum Command {\n    Prepare {\n        query: SqlStr,\n        tx: oneshot::Sender<Result<SqliteStatement, Error>>,\n    },\n    #[cfg(feature = \"offline\")]\n    Describe {\n        query: SqlStr,\n        tx: oneshot::Sender<Result<sqlx_core::describe::Describe<crate::Sqlite>, Error>>,\n    },\n    Execute {\n        query: SqlStr,\n        arguments: Option<SqliteArguments>,\n        persistent: bool,\n        tx: flume::Sender<Result<Either<SqliteQueryResult, SqliteRow>, Error>>,\n        limit: Option<usize>,\n    },\n    #[cfg(feature = \"deserialize\")]\n    Serialize {\n        schema: Option<SchemaName>,\n        tx: oneshot::Sender<Result<SqliteOwnedBuf, Error>>,\n    },\n    #[cfg(feature = \"deserialize\")]\n    Deserialize {\n        schema: Option<SchemaName>,\n        data: SqliteOwnedBuf,\n        read_only: bool,\n        tx: oneshot::Sender<Result<(), Error>>,\n    },\n    Begin {\n        tx: rendezvous_oneshot::Sender<Result<(), Error>>,\n        statement: Option<SqlStr>,\n    },\n    Commit {\n        tx: rendezvous_oneshot::Sender<Result<(), Error>>,\n    },\n    Rollback {\n        tx: Option<rendezvous_oneshot::Sender<Result<(), Error>>>,\n    },\n    UnlockDb,\n    ClearCache {\n        tx: oneshot::Sender<()>,\n    },\n    Ping {\n        tx: oneshot::Sender<()>,\n    },\n    Shutdown {\n        tx: oneshot::Sender<()>,\n    },\n}\n\nimpl ConnectionWorker {\n    pub(crate) async fn establish(params: EstablishParams) -> Result<Self, Error> {\n        let (establish_tx, establish_rx) = oneshot::channel();\n\n        thread::Builder::new()\n            .name(params.thread_name.clone())\n            .spawn(move || {\n                let (command_tx, command_rx) = flume::bounded(params.command_channel_size);\n\n                let conn = match params.establish() {\n                    Ok(conn) => conn,\n                    Err(e) => {\n                        establish_tx.send(Err(e)).ok();\n                        return;\n                    }\n                };\n\n                let shared = Arc::new(WorkerSharedState {\n                    transaction_depth: AtomicUsize::new(0),\n                    cached_statements_size: AtomicUsize::new(0),\n                    // note: must be fair because in `Command::UnlockDb` we unlock the mutex\n                    // and then immediately try to relock it; an unfair mutex would immediately\n                    // grant us the lock even if another task is waiting.\n                    conn: Mutex::new(conn, true),\n                });\n                let mut conn = shared.conn.try_lock().unwrap();\n\n                if establish_tx\n                    .send(Ok(Self {\n                        command_tx,\n                        shared: Arc::clone(&shared),\n                    }))\n                    .is_err()\n                {\n                    return;\n                }\n\n                // If COMMIT or ROLLBACK is processed but not acknowledged, there would be another\n                // ROLLBACK sent when the `Transaction` drops. We need to ignore it otherwise we\n                // would rollback an already completed transaction.\n                let mut ignore_next_start_rollback = false;\n\n                for (cmd, span) in command_rx {\n                    let _guard = span.enter();\n                    match cmd {\n                        Command::Prepare { query, tx } => {\n                            tx.send(prepare(&mut conn, query)).ok();\n\n                            // This may issue an unnecessary write on failure,\n                            // but it doesn't matter in the grand scheme of things.\n                            update_cached_statements_size(\n                                &conn,\n                                &shared.cached_statements_size,\n                            );\n                        }\n                        #[cfg(feature = \"offline\")]\n                        Command::Describe { query, tx } => {\n                            tx.send(crate::connection::describe::describe(&mut conn, query)).ok();\n                        }\n                        Command::Execute {\n                            query,\n                            arguments,\n                            persistent,\n                            tx,\n                            limit\n                        } => {\n                            let iter = match execute::iter(&mut conn, query, arguments, persistent)\n                            {\n                                Ok(iter) => iter,\n                                Err(e) => {\n                                    tx.send(Err(e)).ok();\n                                    continue;\n                                }\n                            };\n\n                            match limit {\n                                None => {\n                                    for res in iter {\n                                        let has_error = res.is_err();\n                                        if tx.send(res).is_err() || has_error {\n                                            break;\n                                        }\n                                    }\n                                },\n                                Some(limit) => {\n                                    let mut iter = iter;\n                                    let mut rows_returned = 0;\n\n                                    while let Some(res) = iter.next() {\n                                        if let Ok(ok) = &res {\n                                            if ok.is_right() {\n                                                rows_returned += 1;\n                                                if rows_returned >= limit {\n                                                    drop(iter);\n                                                    let _ = tx.send(res);\n                                                    break;\n                                                }\n                                            }\n                                        }\n                                        let has_error = res.is_err();\n                                        if tx.send(res).is_err() || has_error {\n                                            break;\n                                        }\n                                    }\n                                },\n                            }\n\n                            update_cached_statements_size(&conn, &shared.cached_statements_size);\n                        }\n                        Command::Begin { tx, statement } => {\n                            let depth = shared.transaction_depth.load(Ordering::Acquire);\n\n                            let is_custom_statement = statement.is_some();\n                            let statement = match statement {\n                                // custom `BEGIN` statements are not allowed if\n                                // we're already in a transaction (we need to\n                                // issue a `SAVEPOINT` instead)\n                                Some(_) if depth > 0 => {\n                                    if tx.blocking_send(Err(Error::InvalidSavePointStatement)).is_err() {\n                                        break;\n                                    }\n                                    continue;\n                                },\n                                Some(statement) => statement,\n                                None => begin_ansi_transaction_sql(depth),\n                            };\n                            let res =\n                                conn.handle\n                                    .exec(statement.as_str())\n                                    .and_then(|res| {\n                                        if is_custom_statement && !conn.handle.in_transaction() {\n                                            return Err(Error::BeginFailed)\n                                        }\n\n                                        shared.transaction_depth.fetch_add(1, Ordering::Release);\n\n                                        Ok(res)\n                                    });\n                            let res_ok = res.is_ok();\n\n                            if tx.blocking_send(res).is_err() && res_ok {\n                                // The BEGIN was processed but not acknowledged. This means no\n                                // `Transaction` was created and so there is no way to commit /\n                                // rollback this transaction. We need to roll it back\n                                // immediately otherwise it would remain started forever.\n                                if let Err(error) = conn\n                                    .handle\n                                    .exec(rollback_ansi_transaction_sql(depth + 1).as_str())\n                                    .map(|_| {\n                                        shared.transaction_depth.fetch_sub(1, Ordering::Release);\n                                    })\n                                {\n                                    // The rollback failed. To prevent leaving the connection\n                                    // in an inconsistent state we shutdown this worker which\n                                    // causes any subsequent operation on the connection to fail.\n                                    tracing::error!(%error, \"failed to rollback cancelled transaction\");\n                                    break;\n                                }\n                            }\n                        }\n                        Command::Commit { tx } => {\n                            let depth = shared.transaction_depth.load(Ordering::Acquire);\n\n                            let res = if depth > 0 {\n                                conn.handle\n                                    .exec(commit_ansi_transaction_sql(depth).as_str())\n                                    .map(|_| {\n                                        shared.transaction_depth.fetch_sub(1, Ordering::Release);\n                                    })\n                            } else {\n                                Ok(())\n                            };\n                            let res_ok = res.is_ok();\n\n                            if tx.blocking_send(res).is_err() && res_ok {\n                                // The COMMIT was processed but not acknowledged. This means that\n                                // the `Transaction` doesn't know it was committed and will try to\n                                // rollback on drop. We need to ignore that rollback.\n                                ignore_next_start_rollback = true;\n                            }\n                        }\n                        Command::Rollback { tx } => {\n                            if ignore_next_start_rollback && tx.is_none() {\n                                ignore_next_start_rollback = false;\n                                continue;\n                            }\n\n                            let depth = shared.transaction_depth.load(Ordering::Acquire);\n\n                            let res = if depth > 0 {\n                                conn.handle\n                                    .exec(rollback_ansi_transaction_sql(depth).as_str())\n                                    .map(|_| {\n                                        shared.transaction_depth.fetch_sub(1, Ordering::Release);\n                                    })\n                            } else {\n                                Ok(())\n                            };\n\n                            let res_ok = res.is_ok();\n\n                            if let Some(tx) = tx {\n                                if tx.blocking_send(res).is_err() && res_ok {\n                                    // The ROLLBACK was processed but not acknowledged. This means\n                                    // that the `Transaction` doesn't know it was rolled back and\n                                    // will try to rollback again on drop. We need to ignore that\n                                    // rollback.\n                                    ignore_next_start_rollback = true;\n                                }\n                            }\n                        }\n                        #[cfg(feature = \"deserialize\")]\n                        Command::Serialize { schema, tx } => {\n                            tx.send(serialize(&mut conn, schema)).ok();\n                        }\n                        #[cfg(feature = \"deserialize\")]\n                        Command::Deserialize { schema, data, read_only, tx } => {\n                            tx.send(deserialize(&mut conn, schema, data, read_only)).ok();\n                        }\n                        Command::ClearCache { tx } => {\n                            conn.statements.clear();\n                            update_cached_statements_size(&conn, &shared.cached_statements_size);\n                            tx.send(()).ok();\n                        }\n                        Command::UnlockDb => {\n                            drop(conn);\n                            conn = futures_executor::block_on(shared.conn.lock());\n                        }\n                        Command::Ping { tx } => {\n                            tx.send(()).ok();\n                        }\n                        Command::Shutdown { tx } => {\n                            // drop the connection references before sending confirmation\n                            // and ending the command loop\n                            drop(conn);\n                            drop(shared);\n                            let _ = tx.send(());\n                            return;\n                        }\n                    }\n                }\n            })?;\n\n        establish_rx.await.map_err(|_| Error::WorkerCrashed)?\n    }\n\n    pub(crate) async fn prepare(&mut self, query: SqlStr) -> Result<SqliteStatement, Error> {\n        self.oneshot_cmd(|tx| Command::Prepare { query, tx })\n            .await?\n    }\n\n    #[cfg(feature = \"offline\")]\n    pub(crate) async fn describe(\n        &mut self,\n        query: SqlStr,\n    ) -> Result<sqlx_core::describe::Describe<crate::Sqlite>, Error> {\n        self.oneshot_cmd(|tx| Command::Describe { query, tx })\n            .await?\n    }\n\n    pub(crate) async fn execute(\n        &mut self,\n        query: SqlStr,\n        args: Option<SqliteArguments>,\n        chan_size: usize,\n        persistent: bool,\n        limit: Option<usize>,\n    ) -> Result<flume::Receiver<Result<Either<SqliteQueryResult, SqliteRow>, Error>>, Error> {\n        let (tx, rx) = flume::bounded(chan_size);\n\n        self.command_tx\n            .send_async((\n                Command::Execute {\n                    query,\n                    arguments: args,\n                    persistent,\n                    tx,\n                    limit,\n                },\n                Span::current(),\n            ))\n            .await\n            .map_err(|_| Error::WorkerCrashed)?;\n\n        Ok(rx)\n    }\n\n    pub(crate) async fn begin(&mut self, statement: Option<SqlStr>) -> Result<(), Error> {\n        self.oneshot_cmd_with_ack(|tx| Command::Begin { tx, statement })\n            .await?\n    }\n\n    pub(crate) async fn commit(&mut self) -> Result<(), Error> {\n        self.oneshot_cmd_with_ack(|tx| Command::Commit { tx })\n            .await?\n    }\n\n    pub(crate) async fn rollback(&mut self) -> Result<(), Error> {\n        self.oneshot_cmd_with_ack(|tx| Command::Rollback { tx: Some(tx) })\n            .await?\n    }\n\n    pub(crate) fn start_rollback(&mut self) -> Result<(), Error> {\n        self.command_tx\n            .send((Command::Rollback { tx: None }, Span::current()))\n            .map_err(|_| Error::WorkerCrashed)\n    }\n\n    pub(crate) async fn ping(&mut self) -> Result<(), Error> {\n        self.oneshot_cmd(|tx| Command::Ping { tx }).await\n    }\n\n    #[cfg(feature = \"deserialize\")]\n    pub(crate) async fn deserialize(\n        &mut self,\n        schema: Option<SchemaName>,\n        data: SqliteOwnedBuf,\n        read_only: bool,\n    ) -> Result<(), Error> {\n        self.oneshot_cmd(|tx| Command::Deserialize {\n            schema,\n            data,\n            read_only,\n            tx,\n        })\n        .await?\n    }\n\n    #[cfg(feature = \"deserialize\")]\n    pub(crate) async fn serialize(\n        &mut self,\n        schema: Option<SchemaName>,\n    ) -> Result<SqliteOwnedBuf, Error> {\n        self.oneshot_cmd(|tx| Command::Serialize { schema, tx })\n            .await?\n    }\n\n    async fn oneshot_cmd<F, T>(&mut self, command: F) -> Result<T, Error>\n    where\n        F: FnOnce(oneshot::Sender<T>) -> Command,\n    {\n        let (tx, rx) = oneshot::channel();\n\n        self.command_tx\n            .send_async((command(tx), Span::current()))\n            .await\n            .map_err(|_| Error::WorkerCrashed)?;\n\n        rx.await.map_err(|_| Error::WorkerCrashed)\n    }\n\n    async fn oneshot_cmd_with_ack<F, T>(&mut self, command: F) -> Result<T, Error>\n    where\n        F: FnOnce(rendezvous_oneshot::Sender<T>) -> Command,\n    {\n        let (tx, rx) = rendezvous_oneshot::channel();\n\n        self.command_tx\n            .send_async((command(tx), Span::current()))\n            .await\n            .map_err(|_| Error::WorkerCrashed)?;\n\n        rx.recv().await.map_err(|_| Error::WorkerCrashed)\n    }\n\n    pub(crate) async fn clear_cache(&mut self) -> Result<(), Error> {\n        self.oneshot_cmd(|tx| Command::ClearCache { tx }).await\n    }\n\n    pub(crate) async fn unlock_db(&mut self) -> Result<MutexGuard<'_, ConnectionState>, Error> {\n        let (guard, res) = futures_util::future::join(\n            // we need to join the wait queue for the lock before we send the message\n            self.shared.conn.lock(),\n            self.command_tx\n                .send_async((Command::UnlockDb, Span::current())),\n        )\n        .await;\n\n        res.map_err(|_| Error::WorkerCrashed)?;\n\n        Ok(guard)\n    }\n\n    /// Send a command to the worker to shut down the processing thread.\n    ///\n    /// A `WorkerCrashed` error may be returned if the thread has already stopped.\n    pub(crate) fn shutdown(&mut self) -> impl Future<Output = Result<(), Error>> {\n        let (tx, rx) = oneshot::channel();\n\n        let send_res = self\n            .command_tx\n            .send((Command::Shutdown { tx }, Span::current()))\n            .map_err(|_| Error::WorkerCrashed);\n\n        async move {\n            send_res?;\n\n            // wait for the response\n            rx.await.map_err(|_| Error::WorkerCrashed)\n        }\n    }\n}\n\nfn prepare(conn: &mut ConnectionState, query: SqlStr) -> Result<SqliteStatement, Error> {\n    // prepare statement object (or checkout from cache)\n    let statement = conn.statements.get(query.as_str(), true)?;\n\n    let mut parameters = 0;\n    let mut columns = None;\n    let mut column_names = None;\n\n    while let Some(statement) = statement.prepare_next(&mut conn.handle)? {\n        parameters += statement.handle.bind_parameter_count();\n\n        // the first non-empty statement is chosen as the statement we pull columns from\n        if !statement.columns.is_empty() && columns.is_none() {\n            columns = Some(Arc::clone(statement.columns));\n            column_names = Some(Arc::clone(statement.column_names));\n        }\n    }\n\n    Ok(SqliteStatement {\n        sql: query,\n        columns: columns.unwrap_or_default(),\n        column_names: column_names.unwrap_or_default(),\n        parameters,\n    })\n}\n\nfn update_cached_statements_size(conn: &ConnectionState, size: &AtomicUsize) {\n    size.store(conn.statements.len(), Ordering::Release);\n}\n\n// A oneshot channel where send completes only after the receiver receives the value.\nmod rendezvous_oneshot {\n    use super::oneshot::{self, Canceled};\n\n    pub fn channel<T>() -> (Sender<T>, Receiver<T>) {\n        let (inner_tx, inner_rx) = oneshot::channel();\n        (Sender { inner: inner_tx }, Receiver { inner: inner_rx })\n    }\n\n    pub struct Sender<T> {\n        inner: oneshot::Sender<(T, oneshot::Sender<()>)>,\n    }\n\n    impl<T> Sender<T> {\n        pub async fn send(self, value: T) -> Result<(), Canceled> {\n            let (ack_tx, ack_rx) = oneshot::channel();\n            self.inner.send((value, ack_tx)).map_err(|_| Canceled)?;\n            ack_rx.await\n        }\n\n        pub fn blocking_send(self, value: T) -> Result<(), Canceled> {\n            futures_executor::block_on(self.send(value))\n        }\n    }\n\n    pub struct Receiver<T> {\n        inner: oneshot::Receiver<(T, oneshot::Sender<()>)>,\n    }\n\n    impl<T> Receiver<T> {\n        pub async fn recv(self) -> Result<T, Canceled> {\n            let (value, ack_tx) = self.inner.await?;\n            ack_tx.send(()).map_err(|_| Canceled)?;\n            Ok(value)\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/database.rs",
    "content": "pub(crate) use sqlx_core::database::{Database, HasStatementCache};\n\nuse crate::arguments::SqliteArgumentsBuffer;\nuse crate::{\n    SqliteArguments, SqliteColumn, SqliteConnection, SqliteQueryResult, SqliteRow, SqliteStatement,\n    SqliteTransactionManager, SqliteTypeInfo, SqliteValue, SqliteValueRef,\n};\n\n/// Sqlite database driver.\n#[derive(Debug)]\npub struct Sqlite;\n\nimpl Database for Sqlite {\n    type Connection = SqliteConnection;\n\n    type TransactionManager = SqliteTransactionManager;\n\n    type Row = SqliteRow;\n\n    type QueryResult = SqliteQueryResult;\n\n    type Column = SqliteColumn;\n\n    type TypeInfo = SqliteTypeInfo;\n\n    type Value = SqliteValue;\n    type ValueRef<'r> = SqliteValueRef<'r>;\n\n    type Arguments = SqliteArguments;\n    type ArgumentBuffer = SqliteArgumentsBuffer;\n\n    type Statement = SqliteStatement;\n\n    const NAME: &'static str = \"SQLite\";\n\n    const URL_SCHEMES: &'static [&'static str] = &[\"sqlite\"];\n}\n\nimpl HasStatementCache for Sqlite {}\n"
  },
  {
    "path": "sqlx-sqlite/src/error.rs",
    "content": "use std::error::Error as StdError;\nuse std::ffi::CStr;\nuse std::fmt::{self, Display, Formatter};\nuse std::os::raw::c_int;\nuse std::{borrow::Cow, str};\n\nuse libsqlite3_sys::{\n    sqlite3, sqlite3_errmsg, sqlite3_errstr, sqlite3_extended_errcode, SQLITE_CONSTRAINT_CHECK,\n    SQLITE_CONSTRAINT_FOREIGNKEY, SQLITE_CONSTRAINT_NOTNULL, SQLITE_CONSTRAINT_PRIMARYKEY,\n    SQLITE_CONSTRAINT_UNIQUE, SQLITE_ERROR, SQLITE_NOMEM,\n};\n\npub(crate) use sqlx_core::error::*;\n\n// Error Codes And Messages\n// https://www.sqlite.org/c3ref/errcode.html\n\n#[derive(Debug)]\npub struct SqliteError {\n    code: c_int,\n    message: Cow<'static, str>,\n}\n\nimpl SqliteError {\n    pub(crate) unsafe fn new(handle: *mut sqlite3) -> Self {\n        Self::try_new(handle).expect(\"There should be an error\")\n    }\n\n    pub(crate) unsafe fn try_new(handle: *mut sqlite3) -> Option<Self> {\n        // returns the extended result code even when extended result codes are disabled\n        let code: c_int = unsafe { sqlite3_extended_errcode(handle) };\n\n        if code == 0 {\n            return None;\n        }\n\n        // return English-language text that describes the error\n        let message = unsafe {\n            let msg = sqlite3_errmsg(handle);\n            debug_assert!(!msg.is_null());\n\n            str::from_utf8_unchecked(CStr::from_ptr(msg).to_bytes()).to_owned()\n        };\n\n        Some(Self {\n            code,\n            message: message.into(),\n        })\n    }\n\n    /// For errors during extension load, the error message is supplied via a separate pointer\n    #[allow(dead_code)]\n    pub(crate) fn with_message(mut self, error_msg: String) -> Self {\n        self.message = error_msg.into();\n        self\n    }\n\n    #[allow(dead_code)]\n    pub(crate) fn from_code(code: c_int) -> Self {\n        let message = unsafe {\n            let errstr = sqlite3_errstr(code);\n\n            if !errstr.is_null() {\n                // SAFETY: `errstr` is guaranteed to be UTF-8\n                // The lifetime of the string is \"internally managed\";\n                // the implementation just selects from an array of static strings.\n                // We copy to an owned buffer in case `libsqlite3` is dynamically loaded somehow.\n                Cow::Owned(str::from_utf8_unchecked(CStr::from_ptr(errstr).to_bytes()).into())\n            } else {\n                Cow::Borrowed(\"<error message unavailable>\")\n            }\n        };\n\n        SqliteError { code, message }\n    }\n\n    #[allow(dead_code)]\n    pub(crate) fn generic(message: impl Into<Cow<'static, str>>) -> Self {\n        Self {\n            code: SQLITE_ERROR,\n            message: message.into(),\n        }\n    }\n\n    /// Return `SQLITE_NOMEM`.\n    pub(crate) fn nomem() -> Self {\n        Self::from_code(SQLITE_NOMEM)\n    }\n}\n\nimpl Display for SqliteError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        // We include the code as some produce ambiguous messages:\n        // SQLITE_BUSY: \"database is locked\"\n        // SQLITE_LOCKED: \"database table is locked\"\n        // Sadly there's no function to get the string label back from an error code.\n        write!(f, \"(code: {}) {}\", self.code, self.message)\n    }\n}\n\nimpl StdError for SqliteError {}\n\nimpl DatabaseError for SqliteError {\n    #[inline]\n    fn message(&self) -> &str {\n        &self.message\n    }\n\n    /// The extended result code.\n    #[inline]\n    fn code(&self) -> Option<Cow<'_, str>> {\n        Some(format!(\"{}\", self.code).into())\n    }\n\n    #[doc(hidden)]\n    fn as_error(&self) -> &(dyn StdError + Send + Sync + 'static) {\n        self\n    }\n\n    #[doc(hidden)]\n    fn as_error_mut(&mut self) -> &mut (dyn StdError + Send + Sync + 'static) {\n        self\n    }\n\n    #[doc(hidden)]\n    fn into_error(self: Box<Self>) -> Box<dyn StdError + Send + Sync + 'static> {\n        self\n    }\n\n    fn kind(&self) -> ErrorKind {\n        match self.code {\n            SQLITE_CONSTRAINT_UNIQUE | SQLITE_CONSTRAINT_PRIMARYKEY => ErrorKind::UniqueViolation,\n            SQLITE_CONSTRAINT_FOREIGNKEY => ErrorKind::ForeignKeyViolation,\n            SQLITE_CONSTRAINT_NOTNULL => ErrorKind::NotNullViolation,\n            SQLITE_CONSTRAINT_CHECK => ErrorKind::CheckViolation,\n            _ => ErrorKind::Other,\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/lib.rs",
    "content": "//! **SQLite** database driver.\n//!\n//! ### Note: `libsqlite3-sys` Version\n//! This driver uses the `libsqlite3-sys` crate which links the native library for SQLite 3.\n//! Only one version of `libsqlite3-sys` may appear in the dependency tree of your project.\n//!\n//! As of SQLx 0.9.0, the version of `libsqlite3-sys` is now a range instead of any specific version.\n//! See the `Cargo.toml` of the `sqlx-sqlite` crate for the current version range.\n//!\n//! If you are using `rusqlite` or any other crate that indirectly depends on `libsqlite3-sys`,\n//! this should allow Cargo to select a compatible version.\n//!\n//! If Cargo **fails to select a compatible version**, this means the other crate is using\n//! a `libsqlite3-sys` version outside of this range.\n//!\n//! We may increase the *maximum* version of the range at our discretion,\n//! in patch (SemVer-compatible) releases, to allow users to upgrade to newer versions as desired.\n//!\n//! The *minimum* version of the range may be increased over time to drop very old or\n//! insecure versions of SQLite, but this will only occur in major (SemVer-incompatible) releases.\n//!\n//! Note that this means a `cargo update` may increase the `libsqlite3-sys` version,\n//! which could, in rare cases, break your build.\n//!\n//! To prevent this, you can pin the `libsqlite3-sys` version in your own dependencies:\n//!\n//! ```toml\n//! [dependencies]\n//! # for example, if 0.35.0 breaks the build\n//! libsqlite3-sys = \"0.34\"\n//! ```\n//!\n//! ### Static Linking (Default)\n//! The `sqlite` feature enables the `bundled` feature of `libsqlite3-sys`,\n//! which builds SQLite 3 from included source code and statically links it into the final binary.\n//!\n//! This requires some C build tools to be installed on the system; see\n//! [the `rusqlite` README][rusqlite-readme-building] for details.\n//!\n//! This version of SQLite is generally much newer than system-installed versions of SQLite\n//! (especially for LTS Linux distributions), and can be updated with a `cargo update`,\n//! so this is the recommended option for ease of use and keeping up-to-date.\n//!\n//! ### Dynamic linking\n//! To dynamically link to an existing SQLite library, the `sqlite-unbundled` feature can be used\n//! instead.\n//!\n//! This allows updating SQLite independently of SQLx or using forked versions, but you must have\n//! SQLite installed on the system or provide a path to the library at build time (see\n//! [the `rusqlite` README][rusqlite-readme-building] for details).\n//!\n//! Note that this _may_ result in link errors if the SQLite version is too old,\n//! or has [certain features disabled at compile-time](https://www.sqlite.org/compile.html).\n//!\n//! SQLite version `3.20.0` (released August 2018) or newer is recommended.\n//!\n//! **Please check your SQLite version and the flags it was built with before opening\n//!   a GitHub issue because of errors in `libsqlite3-sys`.** Thank you.\n//!\n//! [rusqlite-readme-building]: https://github.com/rusqlite/rusqlite?tab=readme-ov-file#notes-on-building-rusqlite-and-libsqlite3-sys\n//!\n//! ### Optional Features\n//!\n//! The following features\n//!\n\n// SQLite is a C library. All interactions require FFI which is unsafe.\n// All unsafe blocks should have comments pointing to SQLite docs and ensuring that we maintain\n// invariants.\n#![allow(unsafe_code)]\n\n#[macro_use]\nextern crate sqlx_core;\n\nuse std::sync::atomic::AtomicBool;\n\npub use arguments::{SqliteArgumentValue, SqliteArguments, SqliteArgumentsBuffer};\npub use column::SqliteColumn;\n#[cfg(feature = \"deserialize\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"deserialize\")))]\npub use connection::deserialize::SqliteOwnedBuf;\n#[cfg(feature = \"preupdate-hook\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"preupdate-hook\")))]\npub use connection::PreupdateHookResult;\npub use connection::{LockedSqliteHandle, SqliteConnection, SqliteOperation, UpdateHookResult};\npub use database::Sqlite;\npub use error::SqliteError;\npub use options::{\n    SqliteAutoVacuum, SqliteConnectOptions, SqliteJournalMode, SqliteLockingMode, SqliteSynchronous,\n};\npub use query_result::SqliteQueryResult;\npub use row::SqliteRow;\npub use statement::SqliteStatement;\npub use transaction::SqliteTransactionManager;\npub use type_info::SqliteTypeInfo;\npub use value::{SqliteValue, SqliteValueRef};\n\nuse crate::connection::establish::EstablishParams;\n\npub(crate) use sqlx_core::driver_prelude::*;\n\nuse sqlx_core::config;\nuse sqlx_core::describe::Describe;\nuse sqlx_core::error::Error;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::sql_str::{AssertSqlSafe, SqlSafeStr};\n\nmod arguments;\nmod column;\nmod connection;\nmod database;\nmod error;\nmod logger;\nmod options;\nmod query_result;\nmod row;\nmod statement;\nmod transaction;\nmod type_checking;\nmod type_info;\npub mod types;\nmod value;\n\n#[cfg(feature = \"any\")]\npub mod any;\n\n#[cfg(feature = \"regexp\")]\nmod regexp;\n\n#[cfg(feature = \"migrate\")]\nmod migrate;\n\n#[cfg(feature = \"migrate\")]\nmod testing;\n\n/// An alias for [`Pool`][crate::pool::Pool], specialized for SQLite.\npub type SqlitePool = crate::pool::Pool<Sqlite>;\n\n/// An alias for [`PoolOptions`][crate::pool::PoolOptions], specialized for SQLite.\npub type SqlitePoolOptions = crate::pool::PoolOptions<Sqlite>;\n\n/// An alias for [`Executor<'_, Database = Sqlite>`][Executor].\npub trait SqliteExecutor<'c>: Executor<'c, Database = Sqlite> {}\nimpl<'c, T: Executor<'c, Database = Sqlite>> SqliteExecutor<'c> for T {}\n\n/// An alias for [`Transaction`][sqlx_core::transaction::Transaction], specialized for SQLite.\npub type SqliteTransaction<'c> = sqlx_core::transaction::Transaction<'c, Sqlite>;\n\n// NOTE: required due to the lack of lazy normalization\nimpl_into_arguments_for_arguments!(SqliteArguments);\nimpl_column_index_for_row!(SqliteRow);\nimpl_column_index_for_statement!(SqliteStatement);\nimpl_acquire!(Sqlite, SqliteConnection);\n\n// required because some databases have a different handling of NULL\nimpl_encode_for_option!(Sqlite);\n\n/// UNSTABLE: for use by `sqlx-cli` only.\n#[doc(hidden)]\npub static CREATE_DB_WAL: AtomicBool = AtomicBool::new(true);\n\n/// UNSTABLE: for use by `sqlite-macros-core` only.\n#[doc(hidden)]\npub fn describe_blocking(\n    query: &str,\n    database_url: &str,\n    driver_config: &config::drivers::Config,\n) -> Result<Describe<Sqlite>, Error> {\n    let mut opts: SqliteConnectOptions = database_url.parse()?;\n\n    opts = opts.apply_driver_config(&driver_config.sqlite)?;\n\n    let params = EstablishParams::from_options(&opts)?;\n    let mut conn = params.establish()?;\n\n    // Execute any ancillary `PRAGMA`s\n    connection::execute::iter(&mut conn, AssertSqlSafe(opts.pragma_string()), None, false)?\n        .finish()?;\n\n    connection::describe::describe(&mut conn, AssertSqlSafe(query.to_string()).into_sql_str())\n\n    // SQLite database is closed immediately when `conn` is dropped\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/logger.rs",
    "content": "// Bad casts in this module SHOULD NOT result in a SQL injection\n// https://github.com/launchbadge/sqlx/issues/3440\n#![allow(\n    clippy::cast_possible_truncation,\n    clippy::cast_possible_wrap,\n    clippy::cast_sign_loss\n)]\n\nuse crate::connection::intmap::IntMap;\nuse std::collections::HashSet;\nuse std::fmt::Debug;\nuse std::hash::Hash;\n\npub(crate) use sqlx_core::logger::*;\n\n#[derive(Debug)]\npub(crate) enum BranchResult<R: Debug + 'static> {\n    Result(R),\n    Dedup(BranchParent),\n    Halt,\n    Error,\n    GasLimit,\n    LoopLimit,\n    Branched,\n}\n\n#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq, Ord, PartialOrd)]\npub(crate) struct BranchParent {\n    pub id: i64,\n    pub idx: i64,\n}\n\n#[derive(Debug)]\npub(crate) struct InstructionHistory<S: Debug + DebugDiff> {\n    pub program_i: usize,\n    pub state: S,\n}\n\npub(crate) trait DebugDiff {\n    fn diff(&self, prev: &Self) -> String;\n}\n\npub struct QueryPlanLogger<'q, R: Debug + 'static, S: Debug + DebugDiff + 'static, P: Debug> {\n    sql: &'q str,\n    unknown_operations: HashSet<usize>,\n    branch_origins: IntMap<BranchParent>,\n    branch_results: IntMap<BranchResult<R>>,\n    branch_operations: IntMap<IntMap<InstructionHistory<S>>>,\n    program: &'q [P],\n}\n\n/// convert a string into dot format\nfn dot_escape_string(value: impl AsRef<str>) -> String {\n    value\n        .as_ref()\n        .replace('\\\\', r#\"\\\\\"#)\n        .replace('\"', \"'\")\n        .replace('\\n', r#\"\\n\"#)\n        .to_string()\n}\n\nimpl<R: Debug, S: Debug + DebugDiff, P: Debug> core::fmt::Display for QueryPlanLogger<'_, R, S, P> {\n    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n        //writes query plan history in dot format\n        f.write_str(\"digraph {\\n\")?;\n\n        f.write_str(\"subgraph operations {\\n\")?;\n        f.write_str(\"style=\\\"rounded\\\";\\nnode [shape=\\\"point\\\"];\\n\")?;\n\n        let all_states: std::collections::HashMap<BranchParent, &InstructionHistory<S>> = self\n            .branch_operations\n            .iter_entries()\n            .flat_map(\n                |(branch_id, instructions): (i64, &IntMap<InstructionHistory<S>>)| {\n                    instructions.iter_entries().map(\n                        move |(idx, ih): (i64, &InstructionHistory<S>)| {\n                            (BranchParent { id: branch_id, idx }, ih)\n                        },\n                    )\n                },\n            )\n            .collect();\n\n        let mut instruction_uses: IntMap<Vec<BranchParent>> = Default::default();\n        for (k, state) in all_states.iter() {\n            let entry = instruction_uses.get_mut_or_default(&(state.program_i as i64));\n            entry.push(*k);\n        }\n\n        let mut branch_children: std::collections::HashMap<BranchParent, Vec<BranchParent>> =\n            Default::default();\n\n        let mut branched_with_state: std::collections::HashSet<BranchParent> = Default::default();\n\n        for (branch_id, branch_parent) in self.branch_origins.iter_entries() {\n            let entry = branch_children.entry(*branch_parent).or_default();\n            entry.push(BranchParent {\n                id: branch_id,\n                idx: 0,\n            });\n        }\n\n        for (idx, instruction) in self.program.iter().enumerate() {\n            let escaped_instruction = dot_escape_string(format!(\"{:?}\", instruction));\n            write!(\n                f,\n                \"subgraph cluster_{} {{ label=\\\"{}\\\"\",\n                idx, escaped_instruction\n            )?;\n\n            if self.unknown_operations.contains(&idx) {\n                f.write_str(\" style=dashed\")?;\n            }\n\n            f.write_str(\";\\n\")?;\n\n            let mut state_list: std::collections::BTreeMap<\n                String,\n                Vec<(BranchParent, Option<BranchParent>)>,\n            > = Default::default();\n\n            write!(f, \"i{}[style=invis];\", idx)?;\n\n            if let Some(this_instruction_uses) = instruction_uses.get(&(idx as i64)) {\n                for curr_ref in this_instruction_uses.iter() {\n                    if let Some(curr_state) = all_states.get(curr_ref) {\n                        let next_ref = BranchParent {\n                            id: curr_ref.id,\n                            idx: curr_ref.idx + 1,\n                        };\n\n                        if let Some(next_state) = all_states.get(&next_ref) {\n                            let state_diff = next_state.state.diff(&curr_state.state);\n\n                            state_list\n                                .entry(state_diff)\n                                .or_default()\n                                .push((*curr_ref, Some(next_ref)));\n                        } else {\n                            state_list\n                                .entry(Default::default())\n                                .or_default()\n                                .push((*curr_ref, None));\n                        };\n\n                        if let Some(children) = branch_children.get(curr_ref) {\n                            for next_ref in children {\n                                if let Some(next_state) = all_states.get(next_ref) {\n                                    let state_diff = next_state.state.diff(&curr_state.state);\n\n                                    if !state_diff.is_empty() {\n                                        branched_with_state.insert(*next_ref);\n                                    }\n\n                                    state_list\n                                        .entry(state_diff)\n                                        .or_default()\n                                        .push((*curr_ref, Some(*next_ref)));\n                                }\n                            }\n                        };\n                    }\n                }\n\n                for curr_ref in this_instruction_uses {\n                    if branch_children.contains_key(curr_ref) {\n                        write!(f, \"\\\"b{}p{}\\\";\", curr_ref.id, curr_ref.idx)?;\n                    }\n                }\n            } else {\n                write!(f, \"i{}->i{}[style=invis];\", idx - 1, idx)?;\n            }\n\n            for (state_num, (state_diff, ref_list)) in state_list.iter().enumerate() {\n                if !state_diff.is_empty() {\n                    let escaped_state = dot_escape_string(state_diff);\n                    write!(\n                        f,\n                        \"subgraph \\\"cluster_i{}s{}\\\" {{\\nlabel=\\\"{}\\\"\\n\",\n                        idx, state_num, escaped_state\n                    )?;\n                }\n\n                for (curr_ref, next_ref) in ref_list {\n                    if let Some(next_ref) = next_ref {\n                        let next_program_i = all_states\n                            .get(next_ref)\n                            .map(|s| s.program_i.to_string())\n                            .unwrap_or_default();\n\n                        if branched_with_state.contains(next_ref) {\n                            write!(\n                                f,\n                                \"\\\"b{}p{}_b{}p{}\\\"[tooltip=\\\"next:{}\\\"];\",\n                                curr_ref.id,\n                                curr_ref.idx,\n                                next_ref.id,\n                                next_ref.idx,\n                                next_program_i\n                            )?;\n                            continue;\n                        } else {\n                            write!(\n                                f,\n                                \"\\\"b{}p{}\\\"[tooltip=\\\"next:{}\\\"];\",\n                                curr_ref.id, curr_ref.idx, next_program_i\n                            )?;\n                        }\n                    } else {\n                        write!(f, \"\\\"b{}p{}\\\";\", curr_ref.id, curr_ref.idx)?;\n                    }\n                }\n\n                if !state_diff.is_empty() {\n                    f.write_str(\"}\\n\")?;\n                }\n            }\n\n            f.write_str(\"}\\n\")?;\n        }\n\n        f.write_str(\"};\\n\")?; //subgraph operations\n\n        let max_branch_id: i64 = [\n            self.branch_operations.last_index().unwrap_or(0),\n            self.branch_results.last_index().unwrap_or(0),\n            self.branch_results.last_index().unwrap_or(0),\n        ]\n        .into_iter()\n        .max()\n        .unwrap_or(0);\n\n        f.write_str(\"subgraph branches {\\n\")?;\n        for branch_id in 0..=max_branch_id {\n            write!(f, \"subgraph b{}{{\", branch_id)?;\n\n            let branch_num = branch_id as usize;\n            let color_names = [\n                \"blue\",\n                \"red\",\n                \"cyan\",\n                \"yellow\",\n                \"green\",\n                \"magenta\",\n                \"orange\",\n                \"purple\",\n                \"orangered\",\n                \"sienna\",\n                \"olivedrab\",\n                \"pink\",\n            ];\n            let color_name_root = color_names[branch_num % color_names.len()];\n            let color_name_suffix = match (branch_num / color_names.len()) % 4 {\n                0 => \"1\",\n                1 => \"4\",\n                2 => \"3\",\n                3 => \"2\",\n                _ => \"\",\n            }; //colors are easily confused after color_names.len() * 2, and outright reused after color_names.len() * 4\n            write!(\n                f,\n                \"edge [colorscheme=x11 color={}{}];\",\n                color_name_root, color_name_suffix\n            )?;\n\n            let mut instruction_list: Vec<(BranchParent, &InstructionHistory<S>)> = Vec::new();\n            if let Some(parent) = self.branch_origins.get(&branch_id) {\n                if let Some(parent_state) = all_states.get(parent) {\n                    instruction_list.push((*parent, parent_state));\n                }\n            }\n            if let Some(instructions) = self.branch_operations.get(&branch_id) {\n                for instruction in instructions.iter_entries() {\n                    instruction_list.push((\n                        BranchParent {\n                            id: branch_id,\n                            idx: instruction.0,\n                        },\n                        instruction.1,\n                    ))\n                }\n            }\n\n            let mut instructions_iter = instruction_list.into_iter();\n\n            if let Some((cur_ref, _)) = instructions_iter.next() {\n                let mut prev_ref = cur_ref;\n\n                for (cur_ref, _) in instructions_iter {\n                    if branched_with_state.contains(&cur_ref) {\n                        writeln!(\n                            f,\n                            \"\\\"b{}p{}\\\" -> \\\"b{}p{}_b{}p{}\\\" -> \\\"b{}p{}\\\"\",\n                            prev_ref.id,\n                            prev_ref.idx,\n                            prev_ref.id,\n                            prev_ref.idx,\n                            cur_ref.id,\n                            cur_ref.idx,\n                            cur_ref.id,\n                            cur_ref.idx\n                        )?;\n                    } else {\n                        write!(\n                            f,\n                            \"\\\"b{}p{}\\\" -> \\\"b{}p{}\\\";\",\n                            prev_ref.id, prev_ref.idx, cur_ref.id, cur_ref.idx\n                        )?;\n                    }\n                    prev_ref = cur_ref;\n                }\n\n                //draw edge to the result of this branch\n                if let Some(result) = self.branch_results.get(&branch_id) {\n                    if let BranchResult::Dedup(dedup_ref) = result {\n                        write!(\n                            f,\n                            \"\\\"b{}p{}\\\"->\\\"b{}p{}\\\" [style=dotted]\",\n                            prev_ref.id, prev_ref.idx, dedup_ref.id, dedup_ref.idx\n                        )?;\n                    } else {\n                        let escaped_result = dot_escape_string(format!(\"{:?}\", result));\n                        write!(\n                            f,\n                            \"\\\"b{}p{}\\\" ->\\\"{}\\\"; \\\"{}\\\" [shape=box];\",\n                            prev_ref.id, prev_ref.idx, escaped_result, escaped_result\n                        )?;\n                    }\n                } else {\n                    write!(\n                        f,\n                        \"\\\"b{}p{}\\\" ->\\\"NoResult\\\"; \\\"NoResult\\\" [shape=box];\",\n                        prev_ref.id, prev_ref.idx\n                    )?;\n                }\n            }\n            f.write_str(\"};\\n\")?;\n        }\n        f.write_str(\"};\\n\")?; //branches\n\n        f.write_str(\"}\\n\")?;\n        Ok(())\n    }\n}\n\nimpl<'q, R: Debug, S: Debug + DebugDiff, P: Debug> QueryPlanLogger<'q, R, S, P> {\n    pub fn new(sql: &'q str, program: &'q [P]) -> Self {\n        Self {\n            sql,\n            unknown_operations: HashSet::new(),\n            branch_origins: IntMap::new(),\n            branch_results: IntMap::new(),\n            branch_operations: IntMap::new(),\n            program,\n        }\n    }\n\n    pub fn log_enabled(&self) -> bool {\n        log::log_enabled!(target: \"sqlx::explain\", log::Level::Trace)\n            || private_tracing_dynamic_enabled!(target: \"sqlx::explain\", tracing::Level::TRACE)\n    }\n\n    pub fn add_branch<I: Copy>(&mut self, state: I, parent: &BranchParent)\n    where\n        BranchParent: From<I>,\n    {\n        if !self.log_enabled() {\n            return;\n        }\n        let branch: BranchParent = BranchParent::from(state);\n        self.branch_origins.insert(branch.id, *parent);\n    }\n\n    pub fn add_operation<I: Copy>(&mut self, program_i: usize, state: I)\n    where\n        BranchParent: From<I>,\n        S: From<I>,\n    {\n        if !self.log_enabled() {\n            return;\n        }\n        let branch: BranchParent = BranchParent::from(state);\n        let state: S = S::from(state);\n        self.branch_operations\n            .get_mut_or_default(&branch.id)\n            .insert(branch.idx, InstructionHistory { program_i, state });\n    }\n\n    pub fn add_result<I>(&mut self, state: I, result: BranchResult<R>)\n    where\n        BranchParent: for<'a> From<&'a I>,\n        S: From<I>,\n    {\n        if !self.log_enabled() {\n            return;\n        }\n        let branch: BranchParent = BranchParent::from(&state);\n        self.branch_results.insert(branch.id, result);\n    }\n\n    pub fn add_unknown_operation(&mut self, operation: usize) {\n        if !self.log_enabled() {\n            return;\n        }\n        self.unknown_operations.insert(operation);\n    }\n\n    pub fn finish(&self) {\n        if !self.log_enabled() {\n            return;\n        }\n\n        let mut summary = parse_query_summary(self.sql);\n\n        let sql = if summary != self.sql {\n            summary.push_str(\" …\");\n            format!(\n                \"\\n\\n{}\\n\",\n                self.sql /*\n                         sqlformat::format(\n                             self.sql,\n                             &sqlformat::QueryParams::None,\n                             sqlformat::FormatOptions::default()\n                         )\n                         */\n            )\n        } else {\n            String::new()\n        };\n\n        sqlx_core::private_tracing_dynamic_event!(\n            target: \"sqlx::explain\",\n            tracing::Level::TRACE,\n            \"{}; program:\\n{}\\n\\n{:?}\", summary, self, sql\n        );\n    }\n}\n\nimpl<R: Debug, S: Debug + DebugDiff, P: Debug> Drop for QueryPlanLogger<'_, R, S, P> {\n    fn drop(&mut self) {\n        self.finish();\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/migrate.rs",
    "content": "use crate::connection::{ConnectOptions, Connection};\nuse crate::error::Error;\nuse crate::executor::Executor;\nuse crate::fs;\nuse crate::migrate::MigrateError;\nuse crate::migrate::{AppliedMigration, Migration};\nuse crate::migrate::{Migrate, MigrateDatabase};\nuse crate::query::query;\nuse crate::query_as::query_as;\nuse crate::{Sqlite, SqliteConnectOptions, SqliteConnection, SqliteJournalMode};\nuse futures_core::future::BoxFuture;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse std::str::FromStr;\nuse std::sync::atomic::Ordering;\nuse std::time::Duration;\nuse std::time::Instant;\n\npub(crate) use sqlx_core::migrate::*;\nuse sqlx_core::query_scalar::query_scalar;\n\nimpl MigrateDatabase for Sqlite {\n    async fn create_database(url: &str) -> Result<(), Error> {\n        let mut opts = SqliteConnectOptions::from_str(url)?.create_if_missing(true);\n\n        // Since it doesn't make sense to include this flag in the connection URL,\n        // we just use an `AtomicBool` to pass it.\n        if super::CREATE_DB_WAL.load(Ordering::Acquire) {\n            opts = opts.journal_mode(SqliteJournalMode::Wal);\n        }\n\n        // Opening a connection to sqlite creates the database\n        opts.connect()\n            .await?\n            // Ensure WAL mode tempfiles are cleaned up\n            .close()\n            .await?;\n\n        Ok(())\n    }\n\n    async fn database_exists(url: &str) -> Result<bool, Error> {\n        let options = SqliteConnectOptions::from_str(url)?;\n\n        if options.in_memory {\n            Ok(true)\n        } else {\n            Ok(options.filename.exists())\n        }\n    }\n\n    async fn drop_database(url: &str) -> Result<(), Error> {\n        let options = SqliteConnectOptions::from_str(url)?;\n\n        if !options.in_memory {\n            fs::remove_file(&*options.filename).await?;\n        }\n\n        Ok(())\n    }\n}\n\nimpl Migrate for SqliteConnection {\n    fn create_schema_if_not_exists<'e>(\n        &'e mut self,\n        schema_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async move {\n            // Check if the schema already exists; if so, don't error.\n            let schema_version: Option<i64> = query_scalar(AssertSqlSafe(format!(\n                \"PRAGMA {schema_name}.schema_version\"\n            )))\n            .fetch_optional(&mut *self)\n            .await?;\n\n            if schema_version.is_some() {\n                return Ok(());\n            }\n\n            Err(MigrateError::CreateSchemasNotSupported(\n                format!(\"cannot create new schema {schema_name}; creation of additional schemas in SQLite requires attaching extra database files\"),\n            ))\n        })\n    }\n\n    fn ensure_migrations_table<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<(), MigrateError>> {\n        Box::pin(async move {\n            // language=SQLite\n            self.execute(AssertSqlSafe(format!(\n                r#\"\nCREATE TABLE IF NOT EXISTS {table_name} (\n    version BIGINT PRIMARY KEY,\n    description TEXT NOT NULL,\n    installed_on TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n    success BOOLEAN NOT NULL,\n    checksum BLOB NOT NULL,\n    execution_time BIGINT NOT NULL\n);\n                \"#\n            )))\n            .await?;\n\n            Ok(())\n        })\n    }\n\n    fn dirty_version<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Option<i64>, MigrateError>> {\n        Box::pin(async move {\n            // language=SQLite\n            let row: Option<(i64,)> = query_as(AssertSqlSafe(format!(\n                \"SELECT version FROM {table_name} WHERE success = false ORDER BY version LIMIT 1\"\n            )))\n            .fetch_optional(self)\n            .await?;\n\n            Ok(row.map(|r| r.0))\n        })\n    }\n\n    fn list_applied_migrations<'e>(\n        &'e mut self,\n        table_name: &'e str,\n    ) -> BoxFuture<'e, Result<Vec<AppliedMigration>, MigrateError>> {\n        Box::pin(async move {\n            // language=SQLite\n            let rows: Vec<(i64, Vec<u8>)> = query_as(AssertSqlSafe(format!(\n                \"SELECT version, checksum FROM {table_name} ORDER BY version\"\n            )))\n            .fetch_all(self)\n            .await?;\n\n            let migrations = rows\n                .into_iter()\n                .map(|(version, checksum)| AppliedMigration {\n                    version,\n                    checksum: checksum.into(),\n                })\n                .collect();\n\n            Ok(migrations)\n        })\n    }\n\n    fn lock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async move { Ok(()) })\n    }\n\n    fn unlock(&mut self) -> BoxFuture<'_, Result<(), MigrateError>> {\n        Box::pin(async move { Ok(()) })\n    }\n\n    fn apply<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async move {\n            let start = Instant::now();\n\n            if migration.no_tx {\n                execute_migration(self, table_name, migration).await?;\n            } else {\n                // Use a single transaction for the actual migration script and the essential bookkeeping so we never\n                // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.\n                // The `execution_time` however can only be measured for the whole transaction. This value _only_ exists for\n                // data lineage and debugging reasons, so it is not super important if it is lost. So we initialize it to -1\n                // and update it once the actual transaction completed.\n                let mut tx = self.begin().await?;\n                execute_migration(&mut tx, table_name, migration).await?;\n                tx.commit().await?;\n            }\n\n            // Update `elapsed_time`.\n            // NOTE: The process may disconnect/die at this point, so the elapsed time value might be lost. We accept\n            //       this small risk since this value is not super important.\n            let elapsed = start.elapsed();\n\n            // language=SQLite\n            #[allow(clippy::cast_possible_truncation)]\n            let _ = query(AssertSqlSafe(format!(\n                r#\"\n    UPDATE {table_name}\n    SET execution_time = ?1\n    WHERE version = ?2\n                \"#\n            )))\n            .bind(elapsed.as_nanos() as i64)\n            .bind(migration.version)\n            .execute(self)\n            .await?;\n\n            Ok(elapsed)\n        })\n    }\n\n    fn revert<'e>(\n        &'e mut self,\n        table_name: &'e str,\n        migration: &'e Migration,\n    ) -> BoxFuture<'e, Result<Duration, MigrateError>> {\n        Box::pin(async move {\n            let start = Instant::now();\n\n            if migration.no_tx {\n                revert_migration(self, table_name, migration).await?;\n            } else {\n                // Use a single transaction for the actual migration script and the essential bookkeeping so we never\n                // execute migrations twice. See https://github.com/launchbadge/sqlx/issues/1966.\n                let mut tx = self.begin().await?;\n                revert_migration(&mut tx, table_name, migration).await?;\n                tx.commit().await?;\n            }\n\n            let elapsed = start.elapsed();\n\n            Ok(elapsed)\n        })\n    }\n}\n\nasync fn execute_migration(\n    conn: &mut SqliteConnection,\n    table_name: &str,\n    migration: &Migration,\n) -> Result<(), MigrateError> {\n    let _ = conn\n        .execute(migration.sql.clone())\n        .await\n        .map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;\n\n    // language=SQLite\n    let _ = query(AssertSqlSafe(format!(\n        r#\"\n    INSERT INTO {table_name} ( version, description, success, checksum, execution_time )\n    VALUES ( ?1, ?2, TRUE, ?3, -1 )\n        \"#\n    )))\n    .bind(migration.version)\n    .bind(&*migration.description)\n    .bind(&*migration.checksum)\n    .execute(conn)\n    .await?;\n\n    Ok(())\n}\n\nasync fn revert_migration(\n    conn: &mut SqliteConnection,\n    table_name: &str,\n    migration: &Migration,\n) -> Result<(), MigrateError> {\n    let _ = conn\n        .execute(migration.sql.clone())\n        .await\n        .map_err(|e| MigrateError::ExecuteMigration(e, migration.version))?;\n\n    // language=SQLite\n    let _ = query(AssertSqlSafe(format!(\n        r#\"\n    DELETE FROM {table_name}\n    WHERE version = ?1\n        \"#\n    )))\n    .bind(migration.version)\n    .execute(conn)\n    .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/auto_vacuum.rs",
    "content": "use crate::error::Error;\nuse std::str::FromStr;\n\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum SqliteAutoVacuum {\n    #[default]\n    None,\n    Full,\n    Incremental,\n}\n\nimpl SqliteAutoVacuum {\n    pub(crate) fn as_str(&self) -> &'static str {\n        match self {\n            SqliteAutoVacuum::None => \"NONE\",\n            SqliteAutoVacuum::Full => \"FULL\",\n            SqliteAutoVacuum::Incremental => \"INCREMENTAL\",\n        }\n    }\n}\n\nimpl FromStr for SqliteAutoVacuum {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        Ok(match &*s.to_ascii_lowercase() {\n            \"none\" => SqliteAutoVacuum::None,\n            \"full\" => SqliteAutoVacuum::Full,\n            \"incremental\" => SqliteAutoVacuum::Incremental,\n\n            _ => {\n                return Err(Error::Configuration(\n                    format!(\"unknown value {s:?} for `auto_vacuum`\").into(),\n                ));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/connect.rs",
    "content": "use crate::{SqliteConnectOptions, SqliteConnection};\nuse log::LevelFilter;\nuse sqlx_core::config;\nuse sqlx_core::connection::ConnectOptions;\nuse sqlx_core::error::Error;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse std::fmt::Write;\nuse std::str::FromStr;\nuse std::time::Duration;\nuse url::Url;\n\nimpl ConnectOptions for SqliteConnectOptions {\n    type Connection = SqliteConnection;\n\n    fn from_url(url: &Url) -> Result<Self, Error> {\n        // SQLite URL parsing is handled specially;\n        // we want to treat the following URLs as equivalent:\n        //\n        // * sqlite:foo.db\n        // * sqlite://foo.db\n        //\n        // If we used `Url::path()`, the latter would return an empty string\n        // because `foo.db` gets parsed as the hostname.\n        Self::from_str(url.as_str())\n    }\n\n    fn to_url_lossy(&self) -> Url {\n        self.build_url()\n    }\n\n    async fn connect(&self) -> Result<Self::Connection, Error>\n    where\n        Self::Connection: Sized,\n    {\n        let mut conn = SqliteConnection::establish(self).await?;\n\n        // Execute PRAGMAs\n        conn.execute(AssertSqlSafe(self.pragma_string())).await?;\n\n        if !self.collations.is_empty() {\n            let mut locked = conn.lock_handle().await?;\n\n            for collation in &self.collations {\n                collation.create(&mut locked.guard.handle)?;\n            }\n        }\n\n        Ok(conn)\n    }\n\n    fn log_statements(mut self, level: LevelFilter) -> Self {\n        self.log_settings.log_statements(level);\n        self\n    }\n\n    fn log_slow_statements(mut self, level: LevelFilter, duration: Duration) -> Self {\n        self.log_settings.log_slow_statements(level, duration);\n        self\n    }\n\n    fn __unstable_apply_driver_config(\n        self,\n        config: &config::drivers::Config,\n    ) -> crate::Result<Self> {\n        self.apply_driver_config(&config.sqlite)\n    }\n}\n\nimpl SqliteConnectOptions {\n    /// Collect all `PRAMGA` commands into a single string\n    pub(crate) fn pragma_string(&self) -> String {\n        let mut string = String::new();\n\n        for (key, opt_value) in &self.pragmas {\n            if let Some(value) = opt_value {\n                write!(string, \"PRAGMA {key} = {value}; \").ok();\n            }\n        }\n\n        string\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/journal_mode.rs",
    "content": "use crate::error::Error;\nuse std::str::FromStr;\n\n/// Refer to [SQLite documentation] for the meaning of the database journaling mode.\n///\n/// [SQLite documentation]: https://www.sqlite.org/pragma.html#pragma_journal_mode\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum SqliteJournalMode {\n    Delete,\n    Truncate,\n    Persist,\n    Memory,\n    #[default]\n    Wal,\n    Off,\n}\n\nimpl SqliteJournalMode {\n    pub(crate) fn as_str(&self) -> &'static str {\n        match self {\n            SqliteJournalMode::Delete => \"DELETE\",\n            SqliteJournalMode::Truncate => \"TRUNCATE\",\n            SqliteJournalMode::Persist => \"PERSIST\",\n            SqliteJournalMode::Memory => \"MEMORY\",\n            SqliteJournalMode::Wal => \"WAL\",\n            SqliteJournalMode::Off => \"OFF\",\n        }\n    }\n}\n\nimpl FromStr for SqliteJournalMode {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        Ok(match &*s.to_ascii_lowercase() {\n            \"delete\" => SqliteJournalMode::Delete,\n            \"truncate\" => SqliteJournalMode::Truncate,\n            \"persist\" => SqliteJournalMode::Persist,\n            \"memory\" => SqliteJournalMode::Memory,\n            \"wal\" => SqliteJournalMode::Wal,\n            \"off\" => SqliteJournalMode::Off,\n\n            _ => {\n                return Err(Error::Configuration(\n                    format!(\"unknown value {s:?} for `journal_mode`\").into(),\n                ));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/locking_mode.rs",
    "content": "use crate::error::Error;\nuse std::str::FromStr;\n\n/// Refer to [SQLite documentation] for the meaning of the connection locking mode.\n///\n/// [SQLite documentation]: https://www.sqlite.org/pragma.html#pragma_locking_mode\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum SqliteLockingMode {\n    #[default]\n    Normal,\n    Exclusive,\n}\n\nimpl SqliteLockingMode {\n    pub(crate) fn as_str(&self) -> &'static str {\n        match self {\n            SqliteLockingMode::Normal => \"NORMAL\",\n            SqliteLockingMode::Exclusive => \"EXCLUSIVE\",\n        }\n    }\n}\n\nimpl FromStr for SqliteLockingMode {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        Ok(match &*s.to_ascii_lowercase() {\n            \"normal\" => SqliteLockingMode::Normal,\n            \"exclusive\" => SqliteLockingMode::Exclusive,\n\n            _ => {\n                return Err(Error::Configuration(\n                    format!(\"unknown value {s:?} for `locking_mode`\").into(),\n                ));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/mod.rs",
    "content": "use std::path::Path;\n\nmod auto_vacuum;\nmod connect;\nmod journal_mode;\nmod locking_mode;\nmod parse;\nmod synchronous;\n\nuse crate::connection::LogSettings;\npub use auto_vacuum::SqliteAutoVacuum;\npub use journal_mode::SqliteJournalMode;\npub use locking_mode::SqliteLockingMode;\nuse std::cmp::Ordering;\nuse std::sync::Arc;\nuse std::{borrow::Cow, time::Duration};\npub use synchronous::SqliteSynchronous;\n\nuse crate::common::DebugFn;\nuse crate::connection::collation::Collation;\nuse sqlx_core::{config, IndexMap};\n\n/// Options and flags which can be used to configure a SQLite connection.\n///\n/// A value of `SqliteConnectOptions` can be parsed from a connection URL,\n/// as described by [SQLite](https://www.sqlite.org/uri.html).\n///\n/// This type also implements [`FromStr`][std::str::FromStr] so you can parse it from a string\n/// containing a connection URL and then further adjust options if necessary (see example below).\n///\n/// | URL | Description |\n/// | -- | -- |\n/// `sqlite::memory:` | Open an in-memory database. |\n/// `sqlite:data.db` | Open the file `data.db` in the current directory. |\n/// `sqlite://data.db` | Open the file `data.db` in the current directory. |\n/// `sqlite:///data.db` | Open the file `data.db` from the root (`/`) directory. |\n/// `sqlite://data.db?mode=ro` | Open the file `data.db` for read-only access. |\n///\n/// # Example\n///\n/// ```rust,no_run\n/// # async fn example() -> sqlx::Result<()> {\n/// use sqlx::ConnectOptions;\n/// use sqlx::sqlite::{SqliteConnectOptions, SqliteJournalMode, SqlitePool};\n/// use std::str::FromStr;\n///\n/// let opts = SqliteConnectOptions::from_str(\"sqlite://data.db\")?\n///     .journal_mode(SqliteJournalMode::Wal)\n///     .read_only(true);\n///\n/// // use in a pool\n/// let pool = SqlitePool::connect_with(opts).await?;\n///\n/// // or connect directly\n/// # let opts = SqliteConnectOptions::from_str(\"sqlite://data.db\")?;\n/// let conn = opts.connect().await?;\n/// #\n/// # Ok(())\n/// # }\n/// ```\n#[derive(Clone, Debug)]\npub struct SqliteConnectOptions {\n    pub(crate) filename: Cow<'static, Path>,\n    pub(crate) in_memory: bool,\n    pub(crate) read_only: bool,\n    pub(crate) create_if_missing: bool,\n    pub(crate) shared_cache: bool,\n    pub(crate) statement_cache_capacity: usize,\n    pub(crate) busy_timeout: Duration,\n    pub(crate) log_settings: LogSettings,\n    pub(crate) immutable: bool,\n    pub(crate) vfs: Option<Cow<'static, str>>,\n\n    pub(crate) pragmas: IndexMap<Cow<'static, str>, Option<Cow<'static, str>>>,\n\n    /// Extensions are specified as a pair of \\<Extension Name : Optional Entry Point>, the majority\n    /// of SQLite extensions will use the default entry points specified in the docs, these should\n    /// be added to the map with a `None` value.\n    /// <https://www.sqlite.org/loadext.html#loading_an_extension>\n    #[cfg(feature = \"load-extension\")]\n    pub(crate) extensions: IndexMap<Cow<'static, str>, Option<Cow<'static, str>>>,\n\n    pub(crate) command_channel_size: usize,\n    pub(crate) row_channel_size: usize,\n\n    pub(crate) collations: Vec<Collation>,\n\n    pub(crate) serialized: bool,\n    pub(crate) thread_name: Arc<DebugFn<dyn Fn(u64) -> String + Send + Sync + 'static>>,\n\n    pub(crate) optimize_on_close: OptimizeOnClose,\n\n    #[cfg(feature = \"regexp\")]\n    pub(crate) register_regexp_function: bool,\n}\n\n#[derive(Clone, Debug)]\npub enum OptimizeOnClose {\n    Enabled { analysis_limit: Option<u32> },\n    Disabled,\n}\n\nimpl Default for SqliteConnectOptions {\n    fn default() -> Self {\n        Self::new()\n    }\n}\n\nimpl SqliteConnectOptions {\n    /// Construct `Self` with default options.\n    ///\n    /// See the source of this method for the current defaults.\n    pub fn new() -> Self {\n        let mut pragmas: IndexMap<Cow<'static, str>, Option<Cow<'static, str>>> = IndexMap::new();\n\n        // Standard pragmas\n        //\n        // Most of these don't actually need to be sent because they would be set to their\n        // default values anyway. See the SQLite documentation for default values of these PRAGMAs:\n        // https://www.sqlite.org/pragma.html\n        //\n        // However, by inserting into the map here, we can ensure that they're set in the proper\n        // order, even if they're overwritten later by their respective setters or\n        // directly by `pragma()`\n\n        // SQLCipher special case: if the `key` pragma is set, it must be executed first.\n        pragmas.insert(\"key\".into(), None);\n\n        // Other SQLCipher pragmas that has to be after the key, but before any other operation on the database.\n        // https://www.zetetic.net/sqlcipher/sqlcipher-api/\n\n        // Bytes of the database file that is not encrypted\n        // Default for SQLCipher v4 is 0\n        // If greater than zero 'cipher_salt' pragma must be also defined\n        pragmas.insert(\"cipher_plaintext_header_size\".into(), None);\n\n        // Allows to provide salt manually\n        // By default SQLCipher sets salt automatically, use only in conjunction with\n        // 'cipher_plaintext_header_size' pragma\n        pragmas.insert(\"cipher_salt\".into(), None);\n\n        // Number of iterations used in PBKDF2 key derivation.\n        // Default for SQLCipher v4 is 256000\n        pragmas.insert(\"kdf_iter\".into(), None);\n\n        // Define KDF algorithm to be used.\n        // Default for SQLCipher v4 is PBKDF2_HMAC_SHA512.\n        pragmas.insert(\"cipher_kdf_algorithm\".into(), None);\n\n        // Enable or disable HMAC functionality.\n        // Default for SQLCipher v4 is 1.\n        pragmas.insert(\"cipher_use_hmac\".into(), None);\n\n        // Set default encryption settings depending on the version 1,2,3, or 4.\n        pragmas.insert(\"cipher_compatibility\".into(), None);\n\n        // Page size of encrypted database.\n        // Default for SQLCipher v4 is 4096.\n        pragmas.insert(\"cipher_page_size\".into(), None);\n\n        // Choose algorithm used for HMAC.\n        // Default for SQLCipher v4 is HMAC_SHA512.\n        pragmas.insert(\"cipher_hmac_algorithm\".into(), None);\n\n        // Normally, page_size must be set before any other action on the database.\n        // Defaults to 4096 for new databases.\n        pragmas.insert(\"page_size\".into(), None);\n\n        // locking_mode should be set before journal_mode:\n        // https://www.sqlite.org/wal.html#use_of_wal_without_shared_memory\n        pragmas.insert(\"locking_mode\".into(), None);\n\n        // `auto_vacuum` needs to be executed before `journal_mode`, if set.\n        //\n        // Otherwise, a change in the `journal_mode` setting appears to mark even an empty database as dirty,\n        // requiring a `vacuum` command to be executed to actually apply the new `auto_vacuum` setting.\n        pragmas.insert(\"auto_vacuum\".into(), None);\n\n        // Don't set `journal_mode` unless the user requested it.\n        // WAL mode is a permanent setting for created databases and changing into or out of it\n        // requires an exclusive lock that can't be waited on with `sqlite3_busy_timeout()`.\n        // https://github.com/launchbadge/sqlx/pull/1930#issuecomment-1168165414\n        pragmas.insert(\"journal_mode\".into(), None);\n\n        // We choose to enable foreign key enforcement by default, though SQLite normally\n        // leaves it off for backward compatibility: https://www.sqlite.org/foreignkeys.html#fk_enable\n        pragmas.insert(\"foreign_keys\".into(), Some(\"ON\".into()));\n\n        // The `synchronous` pragma defaults to FULL\n        // https://www.sqlite.org/compile.html#default_synchronous.\n        pragmas.insert(\"synchronous\".into(), None);\n\n        // Soft limit on the number of rows that `ANALYZE` touches per index.\n        pragmas.insert(\"analysis_limit\".into(), None);\n\n        Self {\n            filename: Cow::Borrowed(Path::new(\":memory:\")),\n            in_memory: false,\n            read_only: false,\n            create_if_missing: false,\n            shared_cache: false,\n            statement_cache_capacity: 100,\n            busy_timeout: Duration::from_secs(5),\n            log_settings: Default::default(),\n            immutable: false,\n            vfs: None,\n            pragmas,\n            #[cfg(feature = \"load-extension\")]\n            extensions: Default::default(),\n            collations: Default::default(),\n            serialized: false,\n            thread_name: Arc::new(DebugFn(|id| format!(\"sqlx-sqlite-worker-{id}\"))),\n            command_channel_size: 50,\n            row_channel_size: 50,\n            optimize_on_close: OptimizeOnClose::Disabled,\n            #[cfg(feature = \"regexp\")]\n            register_regexp_function: false,\n        }\n    }\n\n    /// Sets the name of the database file.\n    ///\n    /// This is a low-level API, and SQLx will apply no special treatment for `\":memory:\"` as an\n    /// in-memory database using this method. Using [`SqliteConnectOptions::from_str()`][SqliteConnectOptions#from_str] may be\n    /// preferred for simple use cases.\n    pub fn filename(mut self, filename: impl AsRef<Path>) -> Self {\n        self.filename = Cow::Owned(filename.as_ref().to_owned());\n        self\n    }\n\n    /// Gets the current name of the database file.\n    pub fn get_filename(&self) -> &Path {\n        &self.filename\n    }\n\n    /// Set the enforcement of [foreign key constraints](https://www.sqlite.org/pragma.html#pragma_foreign_keys).\n    ///\n    /// SQLx chooses to enable this by default so that foreign keys function as expected,\n    /// compared to other database flavors.\n    pub fn foreign_keys(self, on: bool) -> Self {\n        self.pragma(\"foreign_keys\", if on { \"ON\" } else { \"OFF\" })\n    }\n\n    /// Set the [`SQLITE_OPEN_MEMORY` flag](https://sqlite.org/c3ref/open.html).\n    ///\n    /// By default, this is disabled.\n    pub fn in_memory(mut self, in_memory: bool) -> Self {\n        self.in_memory = in_memory;\n        self\n    }\n\n    /// Set the [`SQLITE_OPEN_SHAREDCACHE` flag](https://sqlite.org/sharedcache.html).\n    ///\n    /// By default, this is disabled.\n    pub fn shared_cache(mut self, on: bool) -> Self {\n        self.shared_cache = on;\n        self\n    }\n\n    /// Sets the [journal mode](https://www.sqlite.org/pragma.html#pragma_journal_mode) for the database connection.\n    ///\n    /// Journal modes are ephemeral per connection, with the exception of the\n    /// [Write-Ahead Log (WAL) mode](https://www.sqlite.org/wal.html).\n    ///\n    /// A database created in WAL mode retains the setting and will apply it to all connections\n    /// opened against it that don't set a `journal_mode`.\n    ///\n    /// Opening a connection to a database created in WAL mode with a different `journal_mode` will\n    /// erase the setting on the database, requiring an exclusive lock to do so.\n    /// You may get a `database is locked` (corresponding to `SQLITE_BUSY`) error if another\n    /// connection is accessing the database file at the same time.\n    ///\n    /// SQLx does not set a journal mode by default, to avoid unintentionally changing a database\n    /// into or out of WAL mode.\n    ///\n    /// The default journal mode for non-WAL databases is `DELETE`, or `MEMORY` for in-memory\n    /// databases.\n    ///\n    /// For consistency, any commands in `sqlx-cli` which create a SQLite database will create it\n    /// in WAL mode.\n    pub fn journal_mode(self, mode: SqliteJournalMode) -> Self {\n        self.pragma(\"journal_mode\", mode.as_str())\n    }\n\n    /// Sets the [locking mode](https://www.sqlite.org/pragma.html#pragma_locking_mode) for the database connection.\n    ///\n    /// The default locking mode is NORMAL.\n    pub fn locking_mode(self, mode: SqliteLockingMode) -> Self {\n        self.pragma(\"locking_mode\", mode.as_str())\n    }\n\n    /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to open the database\n    /// for read-only access.\n    pub fn read_only(mut self, read_only: bool) -> Self {\n        self.read_only = read_only;\n        self\n    }\n\n    /// Sets the [access mode](https://www.sqlite.org/c3ref/open.html) to create the database file\n    /// if the file does not exist.\n    ///\n    /// By default, a new file **will not be created** if one is not found.\n    pub fn create_if_missing(mut self, create: bool) -> Self {\n        self.create_if_missing = create;\n        self\n    }\n\n    /// Sets the capacity of the connection's statement cache in a number of stored\n    /// distinct statements. Caching is handled using LRU, meaning when the\n    /// amount of queries hits the defined limit, the oldest statement will get\n    /// dropped.\n    ///\n    /// The default cache capacity is 100 statements.\n    pub fn statement_cache_capacity(mut self, capacity: usize) -> Self {\n        self.statement_cache_capacity = capacity;\n        self\n    }\n\n    /// Sets a timeout value to wait when the database is locked, before\n    /// returning a busy timeout error.\n    ///\n    /// The default busy timeout is 5 seconds.\n    pub fn busy_timeout(mut self, timeout: Duration) -> Self {\n        self.busy_timeout = timeout;\n        self\n    }\n\n    /// Sets the [synchronous](https://www.sqlite.org/pragma.html#pragma_synchronous) setting for the database connection.\n    ///\n    /// The default synchronous settings is FULL. However, if durability is not a concern,\n    /// then NORMAL is normally all one needs in WAL mode.\n    pub fn synchronous(self, synchronous: SqliteSynchronous) -> Self {\n        self.pragma(\"synchronous\", synchronous.as_str())\n    }\n\n    /// Sets the [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum) setting for the database connection.\n    ///\n    /// The default auto_vacuum setting is NONE.\n    ///\n    /// For existing databases, a change to this value does not take effect unless a\n    /// [`VACUUM` command](https://www.sqlite.org/lang_vacuum.html) is executed.\n    pub fn auto_vacuum(self, auto_vacuum: SqliteAutoVacuum) -> Self {\n        self.pragma(\"auto_vacuum\", auto_vacuum.as_str())\n    }\n\n    /// Sets the [page_size](https://www.sqlite.org/pragma.html#pragma_page_size) setting for the database connection.\n    ///\n    /// The default page_size setting is 4096.\n    ///\n    /// For existing databases, a change to this value does not take effect unless a\n    /// [`VACUUM` command](https://www.sqlite.org/lang_vacuum.html) is executed.\n    /// However, it cannot be changed in WAL mode.\n    pub fn page_size(self, page_size: u32) -> Self {\n        self.pragma(\"page_size\", page_size.to_string())\n    }\n\n    /// Sets custom initial pragma for the database connection.\n    pub fn pragma<K, V>(mut self, key: K, value: V) -> Self\n    where\n        K: Into<Cow<'static, str>>,\n        V: Into<Cow<'static, str>>,\n    {\n        self.pragmas.insert(key.into(), Some(value.into()));\n        self\n    }\n\n    /// Add a custom collation for comparing strings in SQL.\n    ///\n    /// If a collation with the same name already exists, it will be replaced.\n    ///\n    /// See [`sqlite3_create_collation()`](https://www.sqlite.org/c3ref/create_collation.html) for details.\n    ///\n    /// Note this excerpt:\n    /// > The collating function must obey the following properties for all strings A, B, and C:\n    /// >\n    /// > If A==B then B==A.\n    /// > If A==B and B==C then A==C.\n    /// > If A\\<B then B>A.\n    /// > If A<B and B<C then A<C.\n    /// >\n    /// > If a collating function fails any of the above constraints and that collating function is\n    /// > registered and used, then the behavior of SQLite is undefined.\n    pub fn collation<N, F>(mut self, name: N, collate: F) -> Self\n    where\n        N: Into<Arc<str>>,\n        F: Fn(&str, &str) -> Ordering + Send + Sync + 'static,\n    {\n        self.collations.push(Collation::new(name, collate));\n        self\n    }\n\n    /// Set to `true` to signal to SQLite that the database file is on read-only media.\n    ///\n    /// If enabled, SQLite assumes the database file _cannot_ be modified, even by higher\n    /// privileged processes, and so disables locking and change detection. This is intended\n    /// to improve performance but can produce incorrect query results or errors if the file\n    /// _does_ change.\n    ///\n    /// Note that this is different from the `SQLITE_OPEN_READONLY` flag set by\n    /// [`.read_only()`][Self::read_only], though the documentation suggests that this\n    /// does _imply_ `SQLITE_OPEN_READONLY`.\n    ///\n    /// See [`sqlite3_open`](https://www.sqlite.org/capi3ref.html#sqlite3_open) (subheading\n    /// \"URI Filenames\") for details.\n    pub fn immutable(mut self, immutable: bool) -> Self {\n        self.immutable = immutable;\n        self\n    }\n\n    /// Sets the [threading mode](https://www.sqlite.org/threadsafe.html) for the database connection.\n    ///\n    /// The default setting is `false` corresponding to using `OPEN_NOMUTEX`.\n    /// If set to `true` then `OPEN_FULLMUTEX`.\n    ///\n    /// See [open](https://www.sqlite.org/c3ref/open.html) for more details.\n    ///\n    /// ### Note\n    /// Setting this to `true` may help if you are getting access violation errors or segmentation\n    /// faults, but will also incur a significant performance penalty. You should leave this\n    /// set to `false` if at all possible.\n    ///\n    /// If you do end up needing to set this to `true` for some reason, please\n    /// [open an issue](https://github.com/launchbadge/sqlx/issues/new/choose) as this may indicate\n    /// a concurrency bug in SQLx. Please provide clear instructions for reproducing the issue,\n    /// including a sample database schema if applicable.\n    pub fn serialized(mut self, serialized: bool) -> Self {\n        self.serialized = serialized;\n        self\n    }\n\n    /// Provide a callback to generate the name of the background worker thread.\n    ///\n    /// The value passed to the callback is an auto-incremented integer for use as the thread ID.\n    pub fn thread_name(\n        mut self,\n        generator: impl Fn(u64) -> String + Send + Sync + 'static,\n    ) -> Self {\n        self.thread_name = Arc::new(DebugFn(generator));\n        self\n    }\n\n    /// Set the maximum number of commands to buffer for the worker thread before backpressure is\n    /// applied.\n    ///\n    /// Given that most commands sent to the worker thread involve waiting for a result,\n    /// the command channel is unlikely to fill up unless a lot queries are executed in a short\n    /// period but cancelled before their full resultsets are returned.\n    pub fn command_buffer_size(mut self, size: usize) -> Self {\n        self.command_channel_size = size;\n        self\n    }\n\n    /// Set the maximum number of rows to buffer back to the calling task when a query is executed.\n    ///\n    /// If the calling task cannot keep up, backpressure will be applied to the worker thread\n    /// in order to limit CPU and memory usage.\n    pub fn row_buffer_size(mut self, size: usize) -> Self {\n        self.row_channel_size = size;\n        self\n    }\n\n    /// Sets the [`vfs`](https://www.sqlite.org/vfs.html) parameter of the database connection.\n    ///\n    /// The default value is empty, and sqlite will use the default VFS object depending on the\n    /// operating system.\n    pub fn vfs(mut self, vfs_name: impl Into<Cow<'static, str>>) -> Self {\n        self.vfs = Some(vfs_name.into());\n        self\n    }\n\n    /// Add a [SQLite extension](https://www.sqlite.org/loadext.html) to be loaded into the database\n    /// connection at startup, using the default entrypoint.\n    ///\n    /// Most common SQLite extensions can be loaded using this method.\n    /// For extensions where you need to override the entry point,\n    /// use [`.extension_with_entrypoint()`].\n    ///\n    /// Multiple extensions can be loaded by calling this method,\n    /// or [`.extension_with_entrypoint()`] where applicable,\n    /// once for each extension.\n    ///\n    /// Extension loading is only enabled during the initialization of the connection,\n    /// and disabled before `connect()` returns by setting\n    /// [`SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION`] to 0.\n    ///\n    /// This will not enable the SQL `load_extension()` function.\n    ///\n    /// [`SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION`]: https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension\n    /// [`.extension_with_entrypoint()`]: Self::extension_with_entrypoint\n    ///\n    /// # Safety\n    /// This causes arbitrary DLLs on the filesystem to be loaded at runtime,\n    /// which can easily result in undefined behavior, memory corruption,\n    /// or exploitable vulnerabilities if misused.\n    ///\n    /// It is not possible to provide a truly safe version of this API.\n    ///\n    /// Use this method with care, and only load extensions that you trust.\n    ///\n    /// # Example\n    /// ```rust,no_run\n    /// # use sqlx_core::error::Error;\n    /// # use std::str::FromStr;\n    /// # use sqlx_sqlite::SqliteConnectOptions;\n    /// # fn options() -> Result<SqliteConnectOptions, Error> {\n    /// let mut options = SqliteConnectOptions::from_str(\"sqlite://data.db\")?;\n    ///\n    /// // SAFETY: these are trusted extensions.\n    /// unsafe {\n    ///     options = options\n    ///         .extension(\"vsv\")\n    ///         .extension(\"mod_spatialite\");\n    /// }\n    ///     \n    /// # Ok(options)\n    /// # }\n    /// ```\n    #[cfg(feature = \"load-extension\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"sqlite-load-extension\")))]\n    pub unsafe fn extension(mut self, extension_name: impl Into<Cow<'static, str>>) -> Self {\n        self.extensions.insert(extension_name.into(), None);\n        self\n    }\n\n    /// Add a [SQLite extension](https://www.sqlite.org/loadext.html) to be loaded into the database\n    /// connection at startup, overriding the entrypoint.\n    ///\n    /// See also [`.extension()`] for extensions using the standard entrypoint name\n    /// `sqlite3_extension_init` or `sqlite3_<extension name>_init`.\n    ///\n    /// Multiple extensions can be loaded by calling this method,\n    /// or [`.extension()`] where applicable,\n    /// once for each extension.\n    ///\n    /// Extension loading is only enabled during the initialization of the connection,\n    /// and disabled before `connect()` returns by setting\n    /// [`SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION`] to 0.\n    ///\n    /// This will not enable the SQL `load_extension()` function.\n    ///\n    /// [`SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION`]: https://www.sqlite.org/c3ref/c_dbconfig_defensive.html#sqlitedbconfigenableloadextension\n    /// [`.extension_with_entrypoint()`]: Self::extension_with_entrypoint\n    ///\n    /// # Safety\n    /// This causes arbitrary DLLs on the filesystem to be loaded at runtime,\n    /// which can easily result in undefined behavior, memory corruption,\n    /// or exploitable vulnerabilities if misused.\n    ///\n    /// If you specify the wrong entrypoint name, it _may_ simply result in an error,\n    /// or it may end up invoking the wrong routine, leading to undefined behavior.\n    ///\n    /// It is not possible to provide a truly safe version of this API.\n    ///\n    /// Use this method with care, only load extensions that you trust,\n    /// and double-check the entrypoint name with the extension's documentation or source code.\n    #[cfg(feature = \"load-extension\")]\n    #[cfg_attr(docsrs, doc(cfg(feature = \"sqlite-load-extension\")))]\n    pub unsafe fn extension_with_entrypoint(\n        mut self,\n        extension_name: impl Into<Cow<'static, str>>,\n        entry_point: impl Into<Cow<'static, str>>,\n    ) -> Self {\n        self.extensions\n            .insert(extension_name.into(), Some(entry_point.into()));\n        self\n    }\n\n    /// Execute `PRAGMA optimize;` on the SQLite connection before closing.\n    ///\n    /// The SQLite manual recommends using this for long-lived databases.\n    ///\n    /// This will collect and store statistics about the layout of data in your tables to help the query planner make better decisions.\n    /// Over the connection's lifetime, the query planner will make notes about which tables could use up-to-date statistics so this\n    /// command doesn't have to scan the whole database every time. Thus, the best time to execute this is on connection close.\n    ///\n    /// `analysis_limit` sets a soft limit on the maximum number of rows to scan per index.\n    /// It is equivalent to setting [`Self::analysis_limit`] but only takes effect for the `PRAGMA optimize;` call\n    /// and does not affect the behavior of any `ANALYZE` statements made during the connection's lifetime.\n    ///\n    /// If not `None`, the `analysis_limit` here overrides the global `analysis_limit` setting,\n    /// but only for the `PRAGMA optimize;` call.\n    ///\n    /// Not enabled by default.\n    ///\n    /// See [the SQLite manual](https://www.sqlite.org/lang_analyze.html#automatically_running_analyze) for details.\n    pub fn optimize_on_close(\n        mut self,\n        enabled: bool,\n        analysis_limit: impl Into<Option<u32>>,\n    ) -> Self {\n        self.optimize_on_close = if enabled {\n            OptimizeOnClose::Enabled {\n                analysis_limit: (analysis_limit.into()),\n            }\n        } else {\n            OptimizeOnClose::Disabled\n        };\n        self\n    }\n\n    /// Set a soft limit on the number of rows that `ANALYZE` touches per index.\n    ///\n    /// This also affects `PRAGMA optimize` which is set by [Self::optimize_on_close].\n    ///\n    /// The value recommended by SQLite is `400`. There is no default.\n    ///\n    /// See [the SQLite manual](https://www.sqlite.org/lang_analyze.html#approx) for details.\n    pub fn analysis_limit(mut self, limit: impl Into<Option<u32>>) -> Self {\n        if let Some(limit) = limit.into() {\n            return self.pragma(\"analysis_limit\", limit.to_string());\n        }\n        self.pragmas.insert(\"analysis_limit\".into(), None);\n        self\n    }\n\n    /// Register a regexp function that allows using regular expressions in queries.\n    ///\n    /// ```\n    /// # use std::str::FromStr;\n    /// # use sqlx::{ConnectOptions, Connection, Row};\n    /// # use sqlx_sqlite::SqliteConnectOptions;\n    /// # async fn run() -> sqlx::Result<()> {\n    /// let mut sqlite = SqliteConnectOptions::from_str(\"sqlite://:memory:\")?\n    ///     .with_regexp()\n    ///     .connect()\n    ///     .await?;\n    /// let tables = sqlx::query(\"SELECT name FROM sqlite_schema WHERE name REGEXP 'foo(\\\\d+)bar'\")\n    ///     .fetch_all(&mut sqlite)\n    ///     .await?;\n    /// # Ok(())\n    /// # }\n    /// ```\n    ///\n    /// This uses the [`regex`] crate, and is only enabled when you enable the `regex` feature is enabled on sqlx\n    #[cfg(feature = \"regexp\")]\n    pub fn with_regexp(mut self) -> Self {\n        self.register_regexp_function = true;\n        self\n    }\n\n    #[cfg_attr(not(feature = \"load-extension\"), expect(unused_mut))]\n    pub(crate) fn apply_driver_config(\n        mut self,\n        config: &config::drivers::SqliteConfig,\n    ) -> crate::Result<Self> {\n        #[cfg(feature = \"load-extension\")]\n        for extension in &config.unsafe_load_extensions {\n            // SAFETY: the documentation warns the user about loading extensions\n            self = unsafe { self.extension(extension.clone()) };\n        }\n\n        #[cfg(not(feature = \"load-extension\"))]\n        if !config.unsafe_load_extensions.is_empty() {\n            return Err(sqlx_core::Error::Configuration(\n                format!(\n                    \"sqlx.toml specifies `drivers.sqlite.unsafe-load-extensions = {:?}` \\\n                 but extension loading is not enabled; \\\n                 enable the `sqlite-load-extension` feature of SQLx to use SQLite extensions\",\n                    config.unsafe_load_extensions,\n                )\n                .into(),\n            ));\n        }\n\n        Ok(self)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/parse.rs",
    "content": "use std::borrow::Cow;\nuse std::path::{Path, PathBuf};\nuse std::str::FromStr;\nuse std::sync::atomic::{AtomicUsize, Ordering};\n\nuse percent_encoding::{percent_decode_str, percent_encode, AsciiSet};\nuse url::Url;\n\nuse crate::error::Error;\nuse crate::SqliteConnectOptions;\n\n// https://www.sqlite.org/uri.html\n\nstatic IN_MEMORY_DB_SEQ: AtomicUsize = AtomicUsize::new(0);\n\nimpl SqliteConnectOptions {\n    pub(crate) fn from_db_and_params(database: &str, params: Option<&str>) -> Result<Self, Error> {\n        let mut options = Self::default();\n\n        if database == \":memory:\" {\n            options.in_memory = true;\n            options.shared_cache = true;\n            let seqno = IN_MEMORY_DB_SEQ.fetch_add(1, Ordering::Relaxed);\n            options.filename = Cow::Owned(PathBuf::from(format!(\"file:sqlx-in-memory-{seqno}\")));\n        } else {\n            // % decode to allow for `?` or `#` in the filename\n            options.filename = Cow::Owned(\n                Path::new(\n                    &*percent_decode_str(database)\n                        .decode_utf8()\n                        .map_err(Error::config)?,\n                )\n                .to_path_buf(),\n            );\n        }\n\n        if let Some(params) = params {\n            for (key, value) in url::form_urlencoded::parse(params.as_bytes()) {\n                match &*key {\n                    // The mode query parameter determines if the new database is opened read-only,\n                    // read-write, read-write and created if it does not exist, or that the\n                    // database is a pure in-memory database that never interacts with disk,\n                    // respectively.\n                    \"mode\" => {\n                        match &*value {\n                            \"ro\" => {\n                                options.read_only = true;\n                            }\n\n                            // default\n                            \"rw\" => {}\n\n                            \"rwc\" => {\n                                options.create_if_missing = true;\n                            }\n\n                            \"memory\" => {\n                                options.in_memory = true;\n                                options.shared_cache = true;\n                            }\n\n                            _ => {\n                                return Err(Error::Configuration(\n                                    format!(\"unknown value {value:?} for `mode`\").into(),\n                                ));\n                            }\n                        }\n                    }\n\n                    // The cache query parameter specifies the cache behaviour across multiple\n                    // connections to the same database within the process. A shared cache is\n                    // essential for persisting data across connections to an in-memory database.\n                    \"cache\" => match &*value {\n                        \"private\" => {\n                            options.shared_cache = false;\n                        }\n\n                        \"shared\" => {\n                            options.shared_cache = true;\n                        }\n\n                        _ => {\n                            return Err(Error::Configuration(\n                                format!(\"unknown value {value:?} for `cache`\").into(),\n                            ));\n                        }\n                    },\n\n                    \"immutable\" => match &*value {\n                        \"true\" | \"1\" => {\n                            options.immutable = true;\n                        }\n                        \"false\" | \"0\" => {\n                            options.immutable = false;\n                        }\n                        _ => {\n                            return Err(Error::Configuration(\n                                format!(\"unknown value {value:?} for `immutable`\").into(),\n                            ));\n                        }\n                    },\n\n                    \"vfs\" => options.vfs = Some(Cow::Owned(value.into_owned())),\n\n                    _ => {\n                        return Err(Error::Configuration(\n                            format!(\"unknown query parameter `{key}` while parsing connection URL\")\n                                .into(),\n                        ));\n                    }\n                }\n            }\n        }\n\n        Ok(options)\n    }\n\n    pub(crate) fn build_url(&self) -> Url {\n        // https://url.spec.whatwg.org/#path-percent-encode-set\n        static PATH_ENCODE_SET: AsciiSet = percent_encoding::CONTROLS\n            .add(b' ')\n            .add(b'\"')\n            .add(b'#')\n            .add(b'<')\n            .add(b'>')\n            .add(b'?')\n            .add(b'`')\n            .add(b'{')\n            .add(b'}');\n\n        let filename_encoded = percent_encode(\n            self.filename.as_os_str().as_encoded_bytes(),\n            &PATH_ENCODE_SET,\n        );\n\n        let mut url = Url::parse(&format!(\"sqlite://{filename_encoded}\"))\n            .expect(\"BUG: generated un-parseable URL\");\n\n        let mode = match (self.in_memory, self.create_if_missing, self.read_only) {\n            (true, _, _) => \"memory\",\n            (false, true, _) => \"rwc\",\n            (false, false, true) => \"ro\",\n            (false, false, false) => \"rw\",\n        };\n        url.query_pairs_mut().append_pair(\"mode\", mode);\n\n        let cache = match self.shared_cache {\n            true => \"shared\",\n            false => \"private\",\n        };\n        url.query_pairs_mut().append_pair(\"cache\", cache);\n\n        if self.immutable {\n            url.query_pairs_mut().append_pair(\"immutable\", \"true\");\n        }\n\n        if let Some(vfs) = &self.vfs {\n            url.query_pairs_mut().append_pair(\"vfs\", vfs);\n        }\n\n        url\n    }\n}\n\nimpl FromStr for SqliteConnectOptions {\n    type Err = Error;\n\n    fn from_str(mut url: &str) -> Result<Self, Self::Err> {\n        // remove scheme from the URL\n        url = url\n            .trim_start_matches(\"sqlite://\")\n            .trim_start_matches(\"sqlite:\");\n\n        let mut database_and_params = url.splitn(2, '?');\n\n        let database = database_and_params.next().unwrap_or_default();\n        let params = database_and_params.next();\n\n        Self::from_db_and_params(database, params)\n    }\n}\n\n#[test]\nfn test_parse_in_memory() -> Result<(), Error> {\n    let options: SqliteConnectOptions = \"sqlite::memory:\".parse()?;\n    assert!(options.in_memory);\n    assert!(options.shared_cache);\n\n    let options: SqliteConnectOptions = \"sqlite://?mode=memory\".parse()?;\n    assert!(options.in_memory);\n    assert!(options.shared_cache);\n\n    let options: SqliteConnectOptions = \"sqlite://:memory:\".parse()?;\n    assert!(options.in_memory);\n    assert!(options.shared_cache);\n\n    let options: SqliteConnectOptions = \"sqlite://?mode=memory&cache=private\".parse()?;\n    assert!(options.in_memory);\n    assert!(!options.shared_cache);\n\n    Ok(())\n}\n\n#[test]\nfn test_parse_read_only() -> Result<(), Error> {\n    let options: SqliteConnectOptions = \"sqlite://a.db?mode=ro\".parse()?;\n    assert!(options.read_only);\n    assert_eq!(&*options.filename.to_string_lossy(), \"a.db\");\n\n    Ok(())\n}\n\n#[test]\nfn test_parse_shared_in_memory() -> Result<(), Error> {\n    let options: SqliteConnectOptions = \"sqlite://a.db?cache=shared\".parse()?;\n    assert!(options.shared_cache);\n    assert_eq!(&*options.filename.to_string_lossy(), \"a.db\");\n\n    Ok(())\n}\n\n#[test]\nfn it_returns_the_parsed_url() -> Result<(), Error> {\n    let url = \"sqlite://test.db?mode=rw&cache=shared\";\n    let options: SqliteConnectOptions = url.parse()?;\n\n    let expected_url = Url::parse(url).unwrap();\n    assert_eq!(options.build_url(), expected_url);\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/options/synchronous.rs",
    "content": "use crate::error::Error;\nuse std::str::FromStr;\n\n/// Refer to [SQLite documentation] for the meaning of various synchronous settings.\n///\n/// [SQLite documentation]: https://www.sqlite.org/pragma.html#pragma_synchronous\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]\npub enum SqliteSynchronous {\n    Off,\n    Normal,\n    #[default]\n    Full,\n    Extra,\n}\n\nimpl SqliteSynchronous {\n    pub(crate) fn as_str(&self) -> &'static str {\n        match self {\n            SqliteSynchronous::Off => \"OFF\",\n            SqliteSynchronous::Normal => \"NORMAL\",\n            SqliteSynchronous::Full => \"FULL\",\n            SqliteSynchronous::Extra => \"EXTRA\",\n        }\n    }\n}\n\nimpl FromStr for SqliteSynchronous {\n    type Err = Error;\n\n    fn from_str(s: &str) -> Result<Self, Error> {\n        Ok(match &*s.to_ascii_lowercase() {\n            \"off\" => SqliteSynchronous::Off,\n            \"normal\" => SqliteSynchronous::Normal,\n            \"full\" => SqliteSynchronous::Full,\n            \"extra\" => SqliteSynchronous::Extra,\n\n            _ => {\n                return Err(Error::Configuration(\n                    format!(\"unknown value {s:?} for `synchronous`\").into(),\n                ));\n            }\n        })\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/query_result.rs",
    "content": "use std::iter::{Extend, IntoIterator};\n\n#[derive(Debug, Default)]\npub struct SqliteQueryResult {\n    pub(super) changes: u64,\n    pub(super) last_insert_rowid: i64,\n}\n\nimpl SqliteQueryResult {\n    pub fn rows_affected(&self) -> u64 {\n        self.changes\n    }\n\n    pub fn last_insert_rowid(&self) -> i64 {\n        self.last_insert_rowid\n    }\n}\n\nimpl Extend<SqliteQueryResult> for SqliteQueryResult {\n    fn extend<T: IntoIterator<Item = SqliteQueryResult>>(&mut self, iter: T) {\n        for elem in iter {\n            self.changes += elem.changes;\n            self.last_insert_rowid = elem.last_insert_rowid;\n        }\n    }\n}\n\n#[cfg(feature = \"any\")]\nimpl From<SqliteQueryResult> for sqlx_core::any::AnyQueryResult {\n    fn from(done: SqliteQueryResult) -> Self {\n        let last_insert_id = match done.last_insert_rowid() {\n            0 => None,\n            n => Some(n),\n        };\n        sqlx_core::any::AnyQueryResult {\n            rows_affected: done.rows_affected(),\n            last_insert_id,\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/regexp.rs",
    "content": "#![deny(missing_docs, clippy::pedantic)]\n#![allow(clippy::cast_sign_loss)] // some lengths returned from sqlite3 are `i32`, but rust needs `usize`\n\n//! Here be dragons\n//!\n//! We need to register a custom REGEX implementation for sqlite\n//! some useful resources:\n//! - rusqlite has an example implementation: <https://docs.rs/rusqlite/0.28.0/rusqlite/functions/index.html>\n//! - sqlite supports registering custom C functions: <https://www.sqlite.org/c3ref/create_function.html>\n//!   - sqlite also supports a `A REGEXP B` syntax, but ONLY if the user implements `regex(B, A)`\n//!   - Note that A and B are indeed swapped: the regex comes first, the field comes second\n//!   - <https://www.sqlite.org/lang_expr.html#regexp>\n//! - sqlx has a way to safely get a sqlite3 pointer:\n//!   - <https://docs.rs/sqlx/0.6.2/sqlx/sqlite/struct.SqliteConnection.html#method.lock_handle>\n//!   - <https://docs.rs/sqlx/0.6.2/sqlx/sqlite/struct.LockedSqliteHandle.html#method.as_raw_handle>\n\nuse libsqlite3_sys as ffi;\nuse log::error;\nuse regex::Regex;\nuse std::sync::Arc;\n\n/// The function name for sqlite3. This must be \"regexp\\0\"\nstatic FN_NAME: &[u8] = b\"regexp\\0\";\n\n/// Register the regex function with sqlite.\n///\n/// Returns the result code of `sqlite3_create_function_v2`\npub fn register(sqlite3: *mut ffi::sqlite3) -> i32 {\n    unsafe {\n        ffi::sqlite3_create_function_v2(\n            //  the database connection\n            sqlite3,\n            // the function name. Must be up to 255 bytes, and 0-terminated\n            FN_NAME.as_ptr().cast(),\n            // the number of arguments this function accepts. We want 2 arguments: The regex and the field\n            2,\n            // we want all our strings to be UTF8, and this function will return the same output with the same inputs\n            ffi::SQLITE_UTF8 | ffi::SQLITE_DETERMINISTIC,\n            // pointer to user data. We're not using user data\n            std::ptr::null_mut(),\n            // xFunc to be executed when we are invoked\n            Some(sqlite3_regexp_func),\n            // xStep, should be NULL for scalar functions\n            None,\n            // xFinal, should be NULL for scalar functions\n            None,\n            // xDestroy, called when this function is deregistered. Should be used to clean up our pointer to user-data\n            None,\n        )\n    }\n}\n\n/// A function to be called on each invocation of `regex(REGEX, FIELD)` from sqlite3\n///\n/// - `ctx`: a pointer to the current sqlite3 context\n/// - `n_arg`: The length of `args`\n/// - `args`: the arguments of this function call\nunsafe extern \"C\" fn sqlite3_regexp_func(\n    ctx: *mut ffi::sqlite3_context,\n    n_arg: i32,\n    args: *mut *mut ffi::sqlite3_value,\n) {\n    // check the arg size. sqlite3 should already ensure this is only 2 args but we want to double check\n    if n_arg != 2 {\n        eprintln!(\"n_arg expected to be 2, is {n_arg}\");\n        ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);\n        return;\n    }\n\n    // arg0: Regex\n    let Some(regex) = get_regex_from_arg(ctx, *args.offset(0), 0) else {\n        return;\n    };\n\n    // arg1: value\n    let Some(value) = get_text_from_arg(ctx, *args.offset(1)) else {\n        return;\n    };\n\n    // if the regex matches the value, set the result int as 1, else as 0\n    if regex.is_match(value) {\n        ffi::sqlite3_result_int(ctx, 1);\n    } else {\n        ffi::sqlite3_result_int(ctx, 0);\n    }\n}\n\n/// Get the regex from the given `arg` at the given `index`.\n///\n/// First this will check to see if the value exists in sqlite's `auxdata`. If it does, that regex will be returned.\n/// sqlite is able to clean up this data at any point, but rust's [`Arc`] guarantees make sure things don't break.\n///\n/// If this value does not exist in `auxdata`, [`try_load_value`] is called and a regex is created from this. If any of\n/// those fail, a message is printed and `None` is returned.\n///\n/// After this regex is created it is stored in `auxdata` and loaded again. If it fails to load, this means that\n/// something inside of sqlite3 went wrong, and we return `None`.\n///\n/// If this value is stored correctly, or if it already existed, the arc reference counter is increased and this value is returned.\nunsafe fn get_regex_from_arg(\n    ctx: *mut ffi::sqlite3_context,\n    arg: *mut ffi::sqlite3_value,\n    index: i32,\n) -> Option<Arc<Regex>> {\n    // try to get the auxdata for this field\n    let ptr = ffi::sqlite3_get_auxdata(ctx, index);\n    if !ptr.is_null() {\n        // if we have it, turn it into an Arc.\n        // we need to make sure to call `increment_strong_count` because the returned `Arc` decrement this when it goes out of scope\n        let ptr = ptr as *const Regex;\n        Arc::increment_strong_count(ptr);\n        return Some(Arc::from_raw(ptr));\n    }\n    // get the text for this field\n    let value = get_text_from_arg(ctx, arg)?;\n    // try to compile it into a regex\n    let regex = match Regex::new(value) {\n        Ok(regex) => Arc::new(regex),\n        Err(e) => {\n            error!(\"Invalid regex {value:?}: {e:?}\");\n            ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);\n            return None;\n        }\n    };\n    // set the regex as auxdata for the next time around\n    ffi::sqlite3_set_auxdata(\n        ctx,\n        index,\n        // make sure to call `Arc::clone` here, setting the strong count to 2.\n        // this will be cleaned up at 2 points:\n        // - when the returned arc goes out of scope\n        // - when sqlite decides to clean it up an calls `cleanup_arc_regex_pointer`\n        Arc::into_raw(Arc::clone(&regex)) as *mut _,\n        Some(cleanup_arc_regex_pointer),\n    );\n    Some(regex)\n}\n\n/// Get a text reference of the value of `arg`. If this value is not a string value, an error is printed and `None` is\n/// returned.\n///\n/// The returned `&str` is valid for lifetime `'a` which can be determined by the caller. This lifetime should **not**\n/// outlive `ctx`.\nunsafe fn get_text_from_arg<'a>(\n    ctx: *mut ffi::sqlite3_context,\n    arg: *mut ffi::sqlite3_value,\n) -> Option<&'a str> {\n    let ty = ffi::sqlite3_value_type(arg);\n    if ty == ffi::SQLITE_TEXT {\n        let ptr = ffi::sqlite3_value_text(arg);\n        let len = ffi::sqlite3_value_bytes(arg);\n        let slice = std::slice::from_raw_parts(ptr.cast(), len as usize);\n        match std::str::from_utf8(slice) {\n            Ok(result) => Some(result),\n            Err(e) => {\n                log::error!(\"Incoming text is not valid UTF8: {e:?}\");\n                ffi::sqlite3_result_error_code(ctx, ffi::SQLITE_CONSTRAINT_FUNCTION);\n                None\n            }\n        }\n    } else {\n        None\n    }\n}\n\n/// Clean up the `Arc<Regex>` that is stored in the given `ptr`.\nunsafe extern \"C\" fn cleanup_arc_regex_pointer(ptr: *mut std::ffi::c_void) {\n    Arc::decrement_strong_count(ptr.cast::<Regex>());\n}\n\n#[cfg(test)]\nmod tests {\n    use sqlx::{ConnectOptions, Row};\n    use std::str::FromStr;\n\n    async fn test_db() -> crate::SqliteConnection {\n        let mut conn = crate::SqliteConnectOptions::from_str(\"sqlite://:memory:\")\n            .unwrap()\n            .with_regexp()\n            .connect()\n            .await\n            .unwrap();\n        sqlx::query(\"CREATE TABLE test (col TEXT NOT NULL)\")\n            .execute(&mut conn)\n            .await\n            .unwrap();\n        for i in 0..10 {\n            sqlx::query(\"INSERT INTO test VALUES (?)\")\n                .bind(format!(\"value {i}\"))\n                .execute(&mut conn)\n                .await\n                .unwrap();\n        }\n        conn\n    }\n\n    #[sqlx::test]\n    async fn test_regexp_does_not_fail() {\n        let mut conn = test_db().await;\n        let result = sqlx::query(\"SELECT col FROM test WHERE col REGEXP 'foo.*bar'\")\n            .fetch_all(&mut conn)\n            .await\n            .expect(\"Could not execute query\");\n        assert!(result.is_empty());\n    }\n\n    #[sqlx::test]\n    async fn test_regexp_filters_correctly() {\n        let mut conn = test_db().await;\n\n        let result = sqlx::query(\"SELECT col FROM test WHERE col REGEXP '.*2'\")\n            .fetch_all(&mut conn)\n            .await\n            .expect(\"Could not execute query\");\n        assert_eq!(result.len(), 1);\n        assert_eq!(result[0].get::<String, usize>(0), String::from(\"value 2\"));\n\n        let result = sqlx::query(\"SELECT col FROM test WHERE col REGEXP '^3'\")\n            .fetch_all(&mut conn)\n            .await\n            .expect(\"Could not execute query\");\n        assert!(result.is_empty());\n    }\n\n    #[sqlx::test]\n    async fn test_invalid_regexp_should_fail() {\n        let mut conn = test_db().await;\n        let result = sqlx::query(\"SELECT col from test WHERE col REGEXP '(?:?)'\")\n            .execute(&mut conn)\n            .await;\n        assert!(matches!(result, Err(sqlx::Error::Database(_))));\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/row.rs",
    "content": "#![allow(clippy::rc_buffer)]\n\nuse std::sync::Arc;\n\nuse sqlx_core::column::ColumnIndex;\nuse sqlx_core::error::Error;\nuse sqlx_core::ext::ustr::UStr;\nuse sqlx_core::row::{debug_row, Row};\nuse sqlx_core::HashMap;\n\nuse crate::statement::StatementHandle;\nuse crate::{Sqlite, SqliteColumn, SqliteValue, SqliteValueRef};\n\n/// Implementation of [`Row`] for SQLite.\npub struct SqliteRow {\n    pub(crate) values: Box<[SqliteValue]>,\n    pub(crate) columns: Arc<Vec<SqliteColumn>>,\n    pub(crate) column_names: Arc<HashMap<UStr, usize>>,\n}\n\n// Accessing values from the statement object is\n// safe across threads as long as we don't call [sqlite3_step]\n\n// we block ourselves from doing that by only exposing\n// a set interface on [StatementHandle]\n\nunsafe impl Send for SqliteRow {}\nunsafe impl Sync for SqliteRow {}\n\nimpl SqliteRow {\n    pub(crate) fn current(\n        statement: &StatementHandle,\n        columns: &Arc<Vec<SqliteColumn>>,\n        column_names: &Arc<HashMap<UStr, usize>>,\n    ) -> Self {\n        let size = statement.column_count();\n        let mut values = Vec::with_capacity(size);\n\n        for i in 0..size {\n            values.push(unsafe {\n                let raw = statement.column_value(i);\n\n                SqliteValue::dup(raw, Some(columns[i].type_info.clone()))\n            });\n        }\n\n        Self {\n            values: values.into_boxed_slice(),\n            columns: Arc::clone(columns),\n            column_names: Arc::clone(column_names),\n        }\n    }\n}\n\nimpl Row for SqliteRow {\n    type Database = Sqlite;\n\n    fn columns(&self) -> &[SqliteColumn] {\n        &self.columns\n    }\n\n    fn try_get_raw<I>(&self, index: I) -> Result<SqliteValueRef<'_>, Error>\n    where\n        I: ColumnIndex<Self>,\n    {\n        let index = index.index(self)?;\n        Ok(SqliteValueRef::value(&self.values[index]))\n    }\n}\n\nimpl ColumnIndex<SqliteRow> for &'_ str {\n    fn index(&self, row: &SqliteRow) -> Result<usize, Error> {\n        row.column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n\nimpl std::fmt::Debug for SqliteRow {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        debug_row(self, f)\n    }\n}\n\n// #[cfg(feature = \"any\")]\n// impl From<SqliteRow> for crate::any::AnyRow {\n//     #[inline]\n//     fn from(row: SqliteRow) -> Self {\n//         crate::any::AnyRow {\n//             columns: row.columns.iter().map(|col| col.clone().into()).collect(),\n//             kind: crate::any::row::AnyRowKind::Sqlite(row),\n//         }\n//     }\n// }\n"
  },
  {
    "path": "sqlx-sqlite/src/statement/handle.rs",
    "content": "use std::ffi::c_void;\nuse std::ffi::CStr;\n\nuse crate::error::{BoxDynError, Error};\nuse crate::type_info::DataType;\nuse crate::{SqliteError, SqliteTypeInfo};\nuse libsqlite3_sys::{\n    sqlite3, sqlite3_bind_blob64, sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64,\n    sqlite3_bind_null, sqlite3_bind_parameter_count, sqlite3_bind_parameter_name,\n    sqlite3_bind_text64, sqlite3_changes, sqlite3_clear_bindings, sqlite3_column_blob,\n    sqlite3_column_bytes, sqlite3_column_count, sqlite3_column_database_name,\n    sqlite3_column_decltype, sqlite3_column_double, sqlite3_column_int, sqlite3_column_int64,\n    sqlite3_column_name, sqlite3_column_origin_name, sqlite3_column_table_name,\n    sqlite3_column_type, sqlite3_column_value, sqlite3_db_handle, sqlite3_finalize, sqlite3_reset,\n    sqlite3_sql, sqlite3_step, sqlite3_stmt, sqlite3_stmt_readonly, sqlite3_table_column_metadata,\n    sqlite3_value, SQLITE_DONE, SQLITE_MISUSE, SQLITE_OK, SQLITE_ROW, SQLITE_TRANSIENT,\n    SQLITE_UTF8,\n};\nuse sqlx_core::column::{ColumnOrigin, TableColumn};\nuse std::os::raw::{c_char, c_int};\nuse std::ptr;\nuse std::ptr::NonNull;\nuse std::slice::from_raw_parts;\nuse std::str::{from_utf8, from_utf8_unchecked};\nuse std::sync::Arc;\n\n#[derive(Debug)]\npub(crate) struct StatementHandle(NonNull<sqlite3_stmt>);\n\n// access to SQLite3 statement handles are safe to send and share between threads\n// as long as the `sqlite3_step` call is serialized.\n\nunsafe impl Send for StatementHandle {}\n\n// Most of the getters below allocate internally, and unsynchronized access is undefined.\n// unsafe impl !Sync for StatementHandle {}\n\nmacro_rules! expect_ret_valid {\n    ($fn_name:ident($($args:tt)*)) => {{\n        let val = $fn_name($($args)*);\n\n        TryFrom::try_from(val)\n            // This likely means UB in SQLite itself or our usage of it;\n            // signed integer overflow is UB in the C standard.\n            .unwrap_or_else(|_| panic!(\"{}() returned invalid value: {val:?}\", stringify!($fn_name)))\n    }}\n}\n\nmacro_rules! check_col_idx {\n    ($idx:ident) => {\n        c_int::try_from($idx).unwrap_or_else(|_| panic!(\"invalid column index: {}\", $idx))\n    };\n}\n\n// might use some of this later\n#[allow(dead_code)]\nimpl StatementHandle {\n    pub(super) fn new(ptr: NonNull<sqlite3_stmt>) -> Self {\n        Self(ptr)\n    }\n\n    #[inline]\n    pub(super) unsafe fn db_handle(&self) -> *mut sqlite3 {\n        // O(c) access to the connection handle for this statement handle\n        // https://sqlite.org/c3ref/db_handle.html\n        sqlite3_db_handle(self.0.as_ptr())\n    }\n\n    pub(crate) fn read_only(&self) -> bool {\n        // https://sqlite.org/c3ref/stmt_readonly.html\n        unsafe { sqlite3_stmt_readonly(self.0.as_ptr()) != 0 }\n    }\n\n    pub(crate) fn sql(&self) -> &str {\n        // https://sqlite.org/c3ref/expanded_sql.html\n        unsafe {\n            let raw = sqlite3_sql(self.0.as_ptr());\n            debug_assert!(!raw.is_null());\n\n            from_utf8_unchecked(CStr::from_ptr(raw).to_bytes())\n        }\n    }\n\n    #[inline]\n    pub(crate) fn last_error(&mut self) -> SqliteError {\n        unsafe { SqliteError::new(self.db_handle()) }\n    }\n\n    #[inline]\n    pub(crate) fn column_count(&self) -> usize {\n        // https://sqlite.org/c3ref/column_count.html\n        unsafe { expect_ret_valid!(sqlite3_column_count(self.0.as_ptr())) }\n    }\n\n    #[inline]\n    pub(crate) fn changes(&self) -> u64 {\n        // returns the number of changes of the *last* statement; not\n        // necessarily this statement.\n        // https://sqlite.org/c3ref/changes.html\n        unsafe { expect_ret_valid!(sqlite3_changes(self.db_handle())) }\n    }\n\n    #[inline]\n    pub(crate) fn column_name(&self, index: usize) -> &str {\n        // https://sqlite.org/c3ref/column_name.html\n        unsafe {\n            let name = sqlite3_column_name(self.0.as_ptr(), check_col_idx!(index));\n            debug_assert!(!name.is_null());\n\n            from_utf8_unchecked(CStr::from_ptr(name).to_bytes())\n        }\n    }\n\n    pub(crate) fn column_origin(&self, index: usize) -> ColumnOrigin {\n        if let Some((table, name)) = self\n            .column_table_name(index)\n            .zip(self.column_origin_name(index))\n        {\n            let table: Arc<str> = self\n                .column_db_name(index)\n                .filter(|&db| db != \"main\")\n                .map_or_else(\n                    || table.into(),\n                    // TODO: check that SQLite returns the names properly quoted if necessary\n                    |db| format!(\"{db}.{table}\").into(),\n                );\n\n            ColumnOrigin::Table(TableColumn {\n                table,\n                name: name.into(),\n            })\n        } else {\n            ColumnOrigin::Expression\n        }\n    }\n\n    fn column_db_name(&self, index: usize) -> Option<&str> {\n        unsafe {\n            let db_name = sqlite3_column_database_name(self.0.as_ptr(), check_col_idx!(index));\n\n            if !db_name.is_null() {\n                Some(from_utf8_unchecked(CStr::from_ptr(db_name).to_bytes()))\n            } else {\n                None\n            }\n        }\n    }\n\n    fn column_table_name(&self, index: usize) -> Option<&str> {\n        unsafe {\n            let table_name = sqlite3_column_table_name(self.0.as_ptr(), check_col_idx!(index));\n\n            if !table_name.is_null() {\n                Some(from_utf8_unchecked(CStr::from_ptr(table_name).to_bytes()))\n            } else {\n                None\n            }\n        }\n    }\n\n    fn column_origin_name(&self, index: usize) -> Option<&str> {\n        unsafe {\n            let origin_name = sqlite3_column_origin_name(self.0.as_ptr(), check_col_idx!(index));\n\n            if !origin_name.is_null() {\n                Some(from_utf8_unchecked(CStr::from_ptr(origin_name).to_bytes()))\n            } else {\n                None\n            }\n        }\n    }\n\n    pub(crate) fn column_type_info(&self, index: usize) -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::from_code(self.column_type(index)))\n    }\n\n    pub(crate) fn column_type_info_opt(&self, index: usize) -> Option<SqliteTypeInfo> {\n        match DataType::from_code(self.column_type(index)) {\n            DataType::Null => None,\n            dt => Some(SqliteTypeInfo(dt)),\n        }\n    }\n\n    #[inline]\n    pub(crate) fn column_decltype(&self, index: usize) -> Option<SqliteTypeInfo> {\n        unsafe {\n            let decl = sqlite3_column_decltype(self.0.as_ptr(), check_col_idx!(index));\n            if decl.is_null() {\n                // If the Nth column of the result set is an expression or subquery,\n                // then a NULL pointer is returned.\n                return None;\n            }\n\n            let decl = from_utf8_unchecked(CStr::from_ptr(decl).to_bytes());\n            let ty: DataType = decl.parse().ok()?;\n\n            Some(SqliteTypeInfo(ty))\n        }\n    }\n\n    pub(crate) fn column_nullable(&self, index: usize) -> Result<Option<bool>, Error> {\n        unsafe {\n            let index = check_col_idx!(index);\n\n            // https://sqlite.org/c3ref/column_database_name.html\n            //\n            // ### Note\n            // The returned string is valid until the prepared statement is destroyed using\n            // sqlite3_finalize() or until the statement is automatically reprepared by the\n            // first call to sqlite3_step() for a particular run or until the same information\n            // is requested again in a different encoding.\n            let db_name = sqlite3_column_database_name(self.0.as_ptr(), index);\n            let table_name = sqlite3_column_table_name(self.0.as_ptr(), index);\n            let origin_name = sqlite3_column_origin_name(self.0.as_ptr(), index);\n\n            if db_name.is_null() || table_name.is_null() || origin_name.is_null() {\n                return Ok(None);\n            }\n\n            let mut not_null: c_int = 0;\n\n            // https://sqlite.org/c3ref/table_column_metadata.html\n            let status = sqlite3_table_column_metadata(\n                self.db_handle(),\n                db_name,\n                table_name,\n                origin_name,\n                // function docs state to provide NULL for return values you don't care about\n                ptr::null_mut(),\n                ptr::null_mut(),\n                &mut not_null,\n                ptr::null_mut(),\n                ptr::null_mut(),\n            );\n\n            if status != SQLITE_OK {\n                // implementation note: the docs for sqlite3_table_column_metadata() specify\n                // that an error can be returned if the column came from a view; however,\n                // experimentally we found that the above functions give us the true origin\n                // for columns in views that came from real tables and so we should never hit this\n                // error; for view columns that are expressions we are given NULL for their origins\n                // so we don't need special handling for that case either.\n                //\n                // this is confirmed in the `tests/sqlite-macros.rs` integration test\n                return Err(SqliteError::new(self.db_handle()).into());\n            }\n\n            Ok(Some(not_null == 0))\n        }\n    }\n\n    // Number Of SQL Parameters\n    #[inline]\n    pub(crate) fn bind_parameter_count(&self) -> usize {\n        // https://www.sqlite.org/c3ref/bind_parameter_count.html\n        unsafe { expect_ret_valid!(sqlite3_bind_parameter_count(self.0.as_ptr())) }\n    }\n\n    // Name Of A Host Parameter\n    // NOTE: The first host parameter has an index of 1, not 0.\n    #[inline]\n    pub(crate) fn bind_parameter_name(&self, index: usize) -> Option<&str> {\n        unsafe {\n            // https://www.sqlite.org/c3ref/bind_parameter_name.html\n            let name = sqlite3_bind_parameter_name(self.0.as_ptr(), check_col_idx!(index));\n            if name.is_null() {\n                return None;\n            }\n\n            Some(from_utf8_unchecked(CStr::from_ptr(name).to_bytes()))\n        }\n    }\n\n    // Binding Values To Prepared Statements\n    // https://www.sqlite.org/c3ref/bind_blob.html\n\n    #[inline]\n    pub(crate) fn bind_blob(&self, index: usize, v: &[u8]) -> c_int {\n        unsafe {\n            sqlite3_bind_blob64(\n                self.0.as_ptr(),\n                check_col_idx!(index),\n                v.as_ptr() as *const c_void,\n                v.len() as u64,\n                SQLITE_TRANSIENT(),\n            )\n        }\n    }\n\n    #[inline]\n    pub(crate) fn bind_text(&self, index: usize, v: &str) -> c_int {\n        #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]\n        let encoding = SQLITE_UTF8 as u8;\n\n        unsafe {\n            sqlite3_bind_text64(\n                self.0.as_ptr(),\n                check_col_idx!(index),\n                v.as_ptr() as *const c_char,\n                v.len() as u64,\n                SQLITE_TRANSIENT(),\n                encoding,\n            )\n        }\n    }\n\n    #[inline]\n    pub(crate) fn bind_int(&self, index: usize, v: i32) -> c_int {\n        unsafe { sqlite3_bind_int(self.0.as_ptr(), check_col_idx!(index), v as c_int) }\n    }\n\n    #[inline]\n    pub(crate) fn bind_int64(&self, index: usize, v: i64) -> c_int {\n        unsafe { sqlite3_bind_int64(self.0.as_ptr(), check_col_idx!(index), v) }\n    }\n\n    #[inline]\n    pub(crate) fn bind_double(&self, index: usize, v: f64) -> c_int {\n        unsafe { sqlite3_bind_double(self.0.as_ptr(), check_col_idx!(index), v) }\n    }\n\n    #[inline]\n    pub(crate) fn bind_null(&self, index: usize) -> c_int {\n        unsafe { sqlite3_bind_null(self.0.as_ptr(), check_col_idx!(index)) }\n    }\n\n    // result values from the query\n    // https://www.sqlite.org/c3ref/column_blob.html\n\n    #[inline]\n    pub(crate) fn column_type(&self, index: usize) -> c_int {\n        unsafe { sqlite3_column_type(self.0.as_ptr(), check_col_idx!(index)) }\n    }\n\n    #[inline]\n    pub(crate) fn column_int(&self, index: usize) -> i32 {\n        unsafe { sqlite3_column_int(self.0.as_ptr(), check_col_idx!(index)) as i32 }\n    }\n\n    #[inline]\n    pub(crate) fn column_int64(&self, index: usize) -> i64 {\n        unsafe { sqlite3_column_int64(self.0.as_ptr(), check_col_idx!(index)) as i64 }\n    }\n\n    #[inline]\n    pub(crate) fn column_double(&self, index: usize) -> f64 {\n        unsafe { sqlite3_column_double(self.0.as_ptr(), check_col_idx!(index)) }\n    }\n\n    #[inline]\n    pub(crate) fn column_value(&self, index: usize) -> *mut sqlite3_value {\n        unsafe { sqlite3_column_value(self.0.as_ptr(), check_col_idx!(index)) }\n    }\n\n    pub(crate) fn column_blob(&self, index: usize) -> &[u8] {\n        let len = unsafe {\n            expect_ret_valid!(sqlite3_column_bytes(self.0.as_ptr(), check_col_idx!(index)))\n        };\n\n        if len == 0 {\n            // empty blobs are NULL so just return an empty slice\n            return &[];\n        }\n\n        let ptr =\n            unsafe { sqlite3_column_blob(self.0.as_ptr(), check_col_idx!(index)) } as *const u8;\n        debug_assert!(!ptr.is_null());\n\n        unsafe { from_raw_parts(ptr, len) }\n    }\n\n    pub(crate) fn column_text(&self, index: usize) -> Result<&str, BoxDynError> {\n        Ok(from_utf8(self.column_blob(index))?)\n    }\n\n    pub(crate) fn clear_bindings(&self) {\n        unsafe { sqlite3_clear_bindings(self.0.as_ptr()) };\n    }\n\n    pub(crate) fn reset(&mut self) -> Result<(), SqliteError> {\n        // SAFETY: we have exclusive access to the handle\n        unsafe {\n            if sqlite3_reset(self.0.as_ptr()) != SQLITE_OK {\n                return Err(SqliteError::new(self.db_handle()));\n            }\n        }\n\n        Ok(())\n    }\n\n    pub(crate) fn step(&mut self) -> Result<bool, SqliteError> {\n        // SAFETY: we have exclusive access to the handle\n        unsafe {\n            #[cfg_attr(not(feature = \"unlock-notify\"), expect(clippy::never_loop))]\n            loop {\n                match sqlite3_step(self.0.as_ptr()) {\n                    SQLITE_ROW => return Ok(true),\n                    SQLITE_DONE => return Ok(false),\n                    SQLITE_MISUSE => panic!(\"misuse!\"),\n                    #[cfg(feature = \"unlock-notify\")]\n                    libsqlite3_sys::SQLITE_LOCKED_SHAREDCACHE => {\n                        // The shared cache is locked by another connection. Wait for unlock\n                        // notification and try again.\n                        super::unlock_notify::wait(self.db_handle())?;\n                        // Need to reset the handle after the unlock\n                        // (https://www.sqlite.org/unlock_notify.html)\n                        sqlite3_reset(self.0.as_ptr());\n                    }\n                    _ => return Err(SqliteError::new(self.db_handle())),\n                }\n            }\n        }\n    }\n}\n\nimpl Drop for StatementHandle {\n    fn drop(&mut self) {\n        // SAFETY: we have exclusive access to the `StatementHandle` here\n        unsafe {\n            // https://sqlite.org/c3ref/finalize.html\n            let status = sqlite3_finalize(self.0.as_ptr());\n            if status == SQLITE_MISUSE {\n                // Panic in case of detected misuse of SQLite API.\n                //\n                // sqlite3_finalize returns it at least in the\n                // case of detected double free, i.e. calling\n                // sqlite3_finalize on already finalized\n                // statement.\n                panic!(\"Detected sqlite3_finalize misuse.\");\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/statement/mod.rs",
    "content": "use crate::column::ColumnIndex;\nuse crate::error::Error;\nuse crate::ext::ustr::UStr;\nuse crate::{Sqlite, SqliteArguments, SqliteColumn, SqliteTypeInfo};\nuse sqlx_core::sql_str::SqlStr;\nuse sqlx_core::{Either, HashMap};\nuse std::sync::Arc;\n\npub(crate) use sqlx_core::statement::*;\n\nmod handle;\n\n#[cfg(feature = \"unlock-notify\")]\npub(super) mod unlock_notify;\nmod r#virtual;\n\npub(crate) use handle::StatementHandle;\npub(crate) use r#virtual::VirtualStatement;\n\n#[derive(Debug, Clone)]\n#[allow(clippy::rc_buffer)]\npub struct SqliteStatement {\n    pub(crate) sql: SqlStr,\n    pub(crate) parameters: usize,\n    pub(crate) columns: Arc<Vec<SqliteColumn>>,\n    pub(crate) column_names: Arc<HashMap<UStr, usize>>,\n}\n\nimpl Statement for SqliteStatement {\n    type Database = Sqlite;\n\n    fn into_sql(self) -> SqlStr {\n        self.sql\n    }\n\n    fn sql(&self) -> &SqlStr {\n        &self.sql\n    }\n\n    fn parameters(&self) -> Option<Either<&[SqliteTypeInfo], usize>> {\n        Some(Either::Right(self.parameters))\n    }\n\n    fn columns(&self) -> &[SqliteColumn] {\n        &self.columns\n    }\n\n    impl_statement_query!(SqliteArguments);\n}\n\nimpl ColumnIndex<SqliteStatement> for &'_ str {\n    fn index(&self, statement: &SqliteStatement) -> Result<usize, Error> {\n        statement\n            .column_names\n            .get(*self)\n            .ok_or_else(|| Error::ColumnNotFound((*self).into()))\n            .copied()\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/statement/unlock_notify.rs",
    "content": "use std::ffi::c_void;\nuse std::os::raw::c_int;\nuse std::slice;\nuse std::sync::{Condvar, Mutex};\n\nuse libsqlite3_sys::{sqlite3, sqlite3_unlock_notify, SQLITE_OK};\n\nuse crate::SqliteError;\n\n// Wait for unlock notification (https://www.sqlite.org/unlock_notify.html)\npub unsafe fn wait(conn: *mut sqlite3) -> Result<(), SqliteError> {\n    let notify = Notify::new();\n\n    if sqlite3_unlock_notify(\n        conn,\n        Some(unlock_notify_cb),\n        &notify as *const Notify as *mut Notify as *mut _,\n    ) != SQLITE_OK\n    {\n        return Err(SqliteError::new(conn));\n    }\n\n    notify.wait();\n\n    Ok(())\n}\n\nunsafe extern \"C\" fn unlock_notify_cb(ptr: *mut *mut c_void, len: c_int) {\n    let ptr = ptr as *mut &Notify;\n    // We don't have a choice; we can't panic and unwind into FFI here.\n    let slice = slice::from_raw_parts(ptr, usize::try_from(len).unwrap_or(0));\n\n    for notify in slice {\n        notify.fire();\n    }\n}\n\nstruct Notify {\n    mutex: Mutex<bool>,\n    condvar: Condvar,\n}\n\nimpl Notify {\n    fn new() -> Self {\n        Self {\n            mutex: Mutex::new(false),\n            condvar: Condvar::new(),\n        }\n    }\n\n    fn wait(&self) {\n        // We only want to wait until the lock is available again.\n        #[allow(let_underscore_lock)]\n        let _ = self\n            .condvar\n            .wait_while(self.mutex.lock().unwrap(), |fired| !*fired)\n            .unwrap();\n    }\n\n    fn fire(&self) {\n        let mut lock = self.mutex.lock().unwrap();\n        *lock = true;\n        self.condvar.notify_one();\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/statement/virtual.rs",
    "content": "#![allow(clippy::rc_buffer)]\n\nuse std::cmp;\nuse std::os::raw::c_char;\nuse std::ptr::{null, null_mut, NonNull};\nuse std::sync::Arc;\n\nuse libsqlite3_sys::{\n    sqlite3, sqlite3_prepare_v3, sqlite3_stmt, SQLITE_OK, SQLITE_PREPARE_PERSISTENT,\n};\n\nuse sqlx_core::bytes::{Buf, Bytes};\nuse sqlx_core::error::Error;\nuse sqlx_core::ext::ustr::UStr;\nuse sqlx_core::{HashMap, SmallVec};\n\nuse crate::connection::ConnectionHandle;\nuse crate::statement::StatementHandle;\nuse crate::{SqliteColumn, SqliteError};\n\n// A virtual statement consists of *zero* or more raw SQLite3 statements. We chop up a SQL statement\n// on `;` to support multiple statements in one query.\n\n#[derive(Debug)]\npub struct VirtualStatement {\n    persistent: bool,\n\n    /// the current index of the actual statement that is executing\n    /// if `None`, no statement is executing and `prepare()` must be called;\n    /// if `Some(self.handles.len())` and `self.tail.is_empty()`,\n    /// there are no more statements to execute and `reset()` must be called\n    index: Option<usize>,\n\n    /// tail of the most recently prepared SQL statement within this container\n    tail: Bytes,\n\n    /// underlying sqlite handles for each inner statement\n    /// a SQL query string in SQLite is broken up into N statements\n    /// we use a [`SmallVec`] to optimize for the most likely case of a single statement\n    pub(crate) handles: SmallVec<[StatementHandle; 1]>,\n\n    // each set of columns\n    pub(crate) columns: SmallVec<[Arc<Vec<SqliteColumn>>; 1]>,\n\n    // each set of column names\n    pub(crate) column_names: SmallVec<[Arc<HashMap<UStr, usize>>; 1]>,\n}\n\npub struct PreparedStatement<'a> {\n    pub(crate) handle: &'a mut StatementHandle,\n    pub(crate) columns: &'a Arc<Vec<SqliteColumn>>,\n    pub(crate) column_names: &'a Arc<HashMap<UStr, usize>>,\n}\n\nimpl VirtualStatement {\n    pub(crate) fn new(mut query: &str, persistent: bool) -> Result<Self, Error> {\n        query = query.trim();\n\n        if query.len() > i32::MAX as usize {\n            return Err(err_protocol!(\n                \"query string must be smaller than {} bytes\",\n                i32::MAX\n            ));\n        }\n\n        Ok(Self {\n            persistent,\n            tail: Bytes::from(String::from(query)),\n            handles: SmallVec::with_capacity(1),\n            index: None,\n            columns: SmallVec::with_capacity(1),\n            column_names: SmallVec::with_capacity(1),\n        })\n    }\n\n    pub(crate) fn prepare_next(\n        &mut self,\n        conn: &mut ConnectionHandle,\n    ) -> Result<Option<PreparedStatement<'_>>, Error> {\n        // increment `self.index` up to `self.handles.len()`\n        self.index = self\n            .index\n            .map(|idx| cmp::min(idx + 1, self.handles.len()))\n            .or(Some(0));\n\n        while self.handles.len() <= self.index.unwrap_or(0) {\n            if self.tail.is_empty() {\n                return Ok(None);\n            }\n\n            if let Some(statement) = prepare(conn.as_ptr(), &mut self.tail, self.persistent)? {\n                let num = statement.column_count();\n\n                let mut columns = Vec::with_capacity(num);\n                let mut column_names = HashMap::with_capacity(num);\n\n                for i in 0..num {\n                    let name: UStr = statement.column_name(i).to_owned().into();\n                    let type_info = statement\n                        .column_decltype(i)\n                        .unwrap_or_else(|| statement.column_type_info(i));\n\n                    columns.push(SqliteColumn {\n                        ordinal: i,\n                        name: name.clone(),\n                        type_info,\n                        origin: statement.column_origin(i),\n                    });\n\n                    column_names.insert(name, i);\n                }\n\n                self.handles.push(statement);\n                self.columns.push(Arc::new(columns));\n                self.column_names.push(Arc::new(column_names));\n            }\n        }\n\n        Ok(self.current())\n    }\n\n    pub fn current(&mut self) -> Option<PreparedStatement<'_>> {\n        self.index\n            .filter(|&idx| idx < self.handles.len())\n            .map(move |idx| PreparedStatement {\n                handle: &mut self.handles[idx],\n                columns: &self.columns[idx],\n                column_names: &self.column_names[idx],\n            })\n    }\n\n    pub fn reset(&mut self) -> Result<(), Error> {\n        self.index = None;\n\n        for handle in self.handles.iter_mut() {\n            handle.reset()?;\n            handle.clear_bindings();\n        }\n\n        Ok(())\n    }\n}\n\nfn prepare(\n    conn: *mut sqlite3,\n    query: &mut Bytes,\n    persistent: bool,\n) -> Result<Option<StatementHandle>, Error> {\n    let mut flags = 0;\n\n    // For some reason, when building with the `sqlcipher` feature enabled\n    // `SQLITE_PREPARE_PERSISTENT` ends up being `i32` instead of `u32`. Crazy, right?\n    #[allow(trivial_casts, clippy::unnecessary_cast)]\n    if persistent {\n        // SQLITE_PREPARE_PERSISTENT\n        //  The SQLITE_PREPARE_PERSISTENT flag is a hint to the query\n        //  planner that the prepared statement will be retained for a long time\n        //  and probably reused many times.\n        flags |= SQLITE_PREPARE_PERSISTENT as u32;\n    }\n\n    while !query.is_empty() {\n        let mut statement_handle: *mut sqlite3_stmt = null_mut();\n        let mut tail: *const c_char = null();\n\n        let query_ptr = query.as_ptr() as *const c_char;\n        let query_len = i32::try_from(query.len()).map_err(|_| {\n            err_protocol!(\n                \"query string too large for SQLite3 API ({} bytes); \\\n                 try breaking it into smaller chunks (< 2 GiB), executed separately\",\n                query.len()\n            )\n        })?;\n\n        // <https://www.sqlite.org/c3ref/prepare.html>\n        let status = unsafe {\n            sqlite3_prepare_v3(\n                conn,\n                query_ptr,\n                query_len,\n                flags,\n                &mut statement_handle,\n                &mut tail,\n            )\n        };\n\n        if status != SQLITE_OK {\n            return Err(unsafe { SqliteError::new(conn).into() });\n        }\n\n        // tail should point to the first byte past the end of the first SQL\n        // statement in zSql. these routines only compile the first statement,\n        // so tail is left pointing to what remains un-compiled.\n\n        let n = (tail as usize) - (query_ptr as usize);\n        query.advance(n);\n\n        if let Some(handle) = NonNull::new(statement_handle) {\n            return Ok(Some(StatementHandle::new(handle)));\n        }\n    }\n\n    Ok(None)\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/testing/mod.rs",
    "content": "use crate::error::Error;\nuse crate::pool::PoolOptions;\nuse crate::testing::{FixtureSnapshot, TestArgs, TestContext, TestSupport};\nuse crate::{Sqlite, SqliteConnectOptions};\nuse std::future::Future;\nuse std::path::{Path, PathBuf};\n\npub(crate) use sqlx_core::testing::*;\n\nconst BASE_PATH: &str = \"target/sqlx/test-dbs\";\n\nimpl TestSupport for Sqlite {\n    fn test_context(\n        args: &TestArgs,\n    ) -> impl Future<Output = Result<TestContext<Self>, Error>> + Send + '_ {\n        test_context(args)\n    }\n\n    async fn cleanup_test(db_name: &str) -> Result<(), Error> {\n        crate::fs::remove_file(db_name).await?;\n        Ok(())\n    }\n\n    async fn cleanup_test_dbs() -> Result<Option<usize>, Error> {\n        crate::fs::remove_dir_all(BASE_PATH).await?;\n        Ok(None)\n    }\n\n    async fn snapshot(_conn: &mut Self::Connection) -> Result<FixtureSnapshot<Self>, Error> {\n        todo!()\n    }\n\n    fn db_name(args: &TestArgs) -> String {\n        convert_path(args.test_path)\n    }\n}\n\nasync fn test_context(args: &TestArgs) -> Result<TestContext<Sqlite>, Error> {\n    let db_path = convert_path(args.test_path);\n\n    if let Some(parent_path) = Path::parent(db_path.as_ref()) {\n        crate::fs::create_dir_all(parent_path)\n            .await\n            .expect(\"failed to create folders\");\n    }\n\n    if Path::exists(db_path.as_ref()) {\n        crate::fs::remove_file(&db_path)\n            .await\n            .expect(\"failed to remove database from previous test run\");\n    }\n\n    Ok(TestContext {\n        connect_opts: SqliteConnectOptions::new()\n            .filename(&db_path)\n            .create_if_missing(true),\n        // This doesn't really matter for SQLite as the databases are independent of each other.\n        // The main limitation is going to be the number of concurrent running tests.\n        pool_opts: PoolOptions::new().max_connections(1000),\n        db_name: db_path,\n    })\n}\n\nfn convert_path(test_path: &str) -> String {\n    let mut path = PathBuf::from(BASE_PATH);\n\n    for segment in test_path.split(\"::\") {\n        path.push(segment);\n    }\n\n    path.set_extension(\"sqlite\");\n\n    path.into_os_string()\n        .into_string()\n        .expect(\"path should be UTF-8\")\n}\n\n#[test]\nfn test_convert_path() {\n    let path = convert_path(\"foo::bar::baz::quux\");\n\n    assert_eq!(path, \"target/sqlx/test-dbs/foo/bar/baz/quux.sqlite\");\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/transaction.rs",
    "content": "use std::future::Future;\n\nuse sqlx_core::transaction::TransactionManager;\nuse sqlx_core::{error::Error, sql_str::SqlStr};\n\nuse crate::{Sqlite, SqliteConnection};\n\n/// Implementation of [`TransactionManager`] for SQLite.\npub struct SqliteTransactionManager;\n\nimpl TransactionManager for SqliteTransactionManager {\n    type Database = Sqlite;\n\n    async fn begin(conn: &mut SqliteConnection, statement: Option<SqlStr>) -> Result<(), Error> {\n        conn.worker.begin(statement).await\n    }\n\n    fn commit(conn: &mut SqliteConnection) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        conn.worker.commit()\n    }\n\n    fn rollback(\n        conn: &mut SqliteConnection,\n    ) -> impl Future<Output = Result<(), Error>> + Send + '_ {\n        conn.worker.rollback()\n    }\n\n    fn start_rollback(conn: &mut SqliteConnection) {\n        conn.worker.start_rollback().ok();\n    }\n\n    fn get_transaction_depth(conn: &SqliteConnection) -> usize {\n        conn.worker.shared.get_transaction_depth()\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/type_checking.rs",
    "content": "use crate::Sqlite;\n#[allow(unused_imports)]\nuse sqlx_core as sqlx;\n\n// f32 is not included below as REAL represents a floating point value\n// stored as an 8-byte IEEE floating point number (i.e. an f64)\n// For more info see: https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes\nimpl_type_checking!(\n    Sqlite {\n        // Note that since the macro checks `column_type_info == <T>::type_info()` first,\n        // we can list `bool` without it being automatically picked for all integer types\n        // due to its `TypeInfo::compatible()` impl.\n        bool,\n        // Since it returns `DataType::Int4` for `type_info()`,\n        // `i32` should only be chosen IFF the column decltype is `INT4`\n        i32,\n        i64,\n        f64,\n        String,\n        Vec<u8>,\n\n        #[cfg(feature = \"uuid\")]\n        sqlx::types::Uuid,\n    },\n    ParamChecking::Weak,\n    // While there are type integrations that must be enabled via Cargo feature,\n    // SQLite's type system doesn't actually have any type that we cannot decode by default.\n    //\n    // The type integrations simply allow the user to skip some intermediate representation,\n    // which is usually TEXT.\n    feature-types: _info => None,\n\n    // The expansion of the macro automatically applies the correct feature name\n    // and checks `[macros.preferred-crates]`\n    datetime-types: {\n        chrono: {\n            sqlx::types::chrono::NaiveDate,\n\n            sqlx::types::chrono::NaiveDateTime,\n\n            sqlx::types::chrono::DateTime<sqlx::types::chrono::Utc>\n                | sqlx::types::chrono::DateTime<_>,\n        },\n        time: {\n            sqlx::types::time::OffsetDateTime,\n\n            sqlx::types::time::PrimitiveDateTime,\n\n            sqlx::types::time::Date,\n        },\n    },\n    numeric-types: {\n        bigdecimal: { },\n        rust_decimal: { },\n    },\n);\n"
  },
  {
    "path": "sqlx-sqlite/src/type_info.rs",
    "content": "use std::fmt::{self, Display, Formatter};\nuse std::os::raw::c_int;\nuse std::str::FromStr;\n\nuse libsqlite3_sys::{SQLITE_BLOB, SQLITE_FLOAT, SQLITE_INTEGER, SQLITE_NULL, SQLITE_TEXT};\n\nuse crate::error::BoxDynError;\n\npub(crate) use sqlx_core::type_info::*;\n\n#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub(crate) enum DataType {\n    // These variants should correspond to `SQLITE_*` type constants.\n    Null,\n    /// Note: SQLite's type system has no notion of integer widths.\n    /// The `INTEGER` type affinity can store up to 8 byte integers,\n    /// making `i64` the only safe choice when mapping integer types to Rust.\n    Integer,\n    Float,\n    Text,\n    Blob,\n\n    // Explicitly not supported: see documentation in `types/mod.rs`\n    #[allow(dead_code)]\n    Numeric,\n\n    // non-standard extensions (chosen based on the column's declared type)\n    /// Chosen if the column's declared type is `BOOLEAN`.\n    Bool,\n    /// Chosen if the column's declared type is `INT4`;\n    /// instructs the macros to use `i32` instead of `i64`.\n    /// Legacy feature; no idea if this is actually used anywhere.\n    Int4,\n    Date,\n    Time,\n    Datetime,\n}\n\n/// Type information for a SQLite type.\n#[derive(Debug, Clone, Eq, PartialEq, Hash)]\n#[cfg_attr(feature = \"offline\", derive(serde::Serialize, serde::Deserialize))]\npub struct SqliteTypeInfo(pub(crate) DataType);\n\nimpl Display for SqliteTypeInfo {\n    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {\n        f.pad(self.name())\n    }\n}\n\nimpl TypeInfo for SqliteTypeInfo {\n    fn is_null(&self) -> bool {\n        matches!(self.0, DataType::Null)\n    }\n\n    fn name(&self) -> &str {\n        match self.0 {\n            DataType::Null => \"NULL\",\n            DataType::Text => \"TEXT\",\n            DataType::Float => \"REAL\",\n            DataType::Blob => \"BLOB\",\n            DataType::Int4 | DataType::Integer => \"INTEGER\",\n            DataType::Numeric => \"NUMERIC\",\n\n            // non-standard extensions\n            DataType::Bool => \"BOOLEAN\",\n            DataType::Date => \"DATE\",\n            DataType::Time => \"TIME\",\n            DataType::Datetime => \"DATETIME\",\n        }\n    }\n}\n\nimpl DataType {\n    pub(crate) fn from_code(code: c_int) -> Self {\n        match code {\n            SQLITE_INTEGER => DataType::Integer,\n            SQLITE_FLOAT => DataType::Float,\n            SQLITE_BLOB => DataType::Blob,\n            SQLITE_NULL => DataType::Null,\n            SQLITE_TEXT => DataType::Text,\n\n            // https://sqlite.org/c3ref/c_blob.html\n            _ => panic!(\"unknown data type code {code}\"),\n        }\n    }\n}\n\n// note: this implementation is particularly important as this is how the macros determine\n//       what Rust type maps to what *declared* SQL type\n// <https://www.sqlite.org/datatype3.html#affname>\nimpl FromStr for DataType {\n    type Err = BoxDynError;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let s = s.to_ascii_lowercase();\n        Ok(match &*s {\n            \"int4\" => DataType::Int4,\n            \"int8\" => DataType::Integer,\n            \"boolean\" | \"bool\" => DataType::Bool,\n\n            \"date\" => DataType::Date,\n            \"time\" => DataType::Time,\n            \"datetime\" | \"timestamp\" => DataType::Datetime,\n\n            _ if s.contains(\"int\") => DataType::Integer,\n\n            _ if s.contains(\"char\") || s.contains(\"clob\") || s.contains(\"text\") => DataType::Text,\n\n            _ if s.contains(\"blob\") => DataType::Blob,\n\n            _ if s.contains(\"real\") || s.contains(\"floa\") || s.contains(\"doub\") => DataType::Float,\n\n            _ => {\n                return Err(format!(\"unknown type: `{s}`\").into());\n            }\n        })\n    }\n}\n\n// #[cfg(feature = \"any\")]\n// impl From<SqliteTypeInfo> for crate::any::AnyTypeInfo {\n//     #[inline]\n//     fn from(ty: SqliteTypeInfo) -> Self {\n//         crate::any::AnyTypeInfo(crate::any::type_info::AnyTypeInfoKind::Sqlite(ty))\n//     }\n// }\n\n#[test]\nfn test_data_type_from_str() -> Result<(), BoxDynError> {\n    assert_eq!(DataType::Int4, \"INT4\".parse()?);\n\n    assert_eq!(DataType::Integer, \"INT\".parse()?);\n    assert_eq!(DataType::Integer, \"INTEGER\".parse()?);\n    assert_eq!(DataType::Integer, \"INTBIG\".parse()?);\n    assert_eq!(DataType::Integer, \"MEDIUMINT\".parse()?);\n\n    assert_eq!(DataType::Integer, \"BIGINT\".parse()?);\n    assert_eq!(DataType::Integer, \"UNSIGNED BIG INT\".parse()?);\n    assert_eq!(DataType::Integer, \"INT8\".parse()?);\n\n    assert_eq!(DataType::Text, \"CHARACTER(20)\".parse()?);\n    assert_eq!(DataType::Text, \"NCHAR(55)\".parse()?);\n    assert_eq!(DataType::Text, \"TEXT\".parse()?);\n    assert_eq!(DataType::Text, \"CLOB\".parse()?);\n\n    assert_eq!(DataType::Blob, \"BLOB\".parse()?);\n\n    assert_eq!(DataType::Float, \"REAL\".parse()?);\n    assert_eq!(DataType::Float, \"FLOAT\".parse()?);\n    assert_eq!(DataType::Float, \"DOUBLE PRECISION\".parse()?);\n\n    assert_eq!(DataType::Bool, \"BOOLEAN\".parse()?);\n    assert_eq!(DataType::Bool, \"BOOL\".parse()?);\n\n    assert_eq!(DataType::Datetime, \"DATETIME\".parse()?);\n    assert_eq!(DataType::Time, \"TIME\".parse()?);\n    assert_eq!(DataType::Date, \"DATE\".parse()?);\n\n    Ok(())\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/bool.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\n\nimpl Type<Sqlite> for bool {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Bool)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Bool | DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for bool {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int((*self).into()));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for bool {\n    fn decode(value: SqliteValueRef<'r>) -> Result<bool, BoxDynError> {\n        Ok(value.int64()? != 0)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/bytes.rs",
    "content": "use std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nuse crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\n\nimpl Type<Sqlite> for [u8] {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Blob)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Blob | DataType::Text)\n    }\n}\n\nimpl Encode<'_, Sqlite> for &'_ [u8] {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self.to_vec())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for &'r [u8] {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.blob_borrowed())\n    }\n}\n\nimpl Encode<'_, Sqlite> for Box<[u8]> {\n    fn encode(self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self.into_vec())));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self.clone().into_vec())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Type<Sqlite> for Vec<u8> {\n    fn type_info() -> SqliteTypeInfo {\n        <&[u8] as Type<Sqlite>>::type_info()\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        <&[u8] as Type<Sqlite>>::compatible(ty)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Vec<u8> {\n    fn encode(self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self)));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self.clone())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for Vec<u8> {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.blob_owned())\n    }\n}\n\nimpl Encode<'_, Sqlite> for Cow<'_, [u8]> {\n    fn encode(self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self.into())));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(self.to_vec())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Arc<[u8]> {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        <Vec<u8> as Encode<'_, Sqlite>>::encode(self.to_vec(), args)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Rc<[u8]> {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        <Vec<u8> as Encode<'_, Sqlite>>::encode(self.to_vec(), args)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/chrono.rs",
    "content": "use std::fmt::Display;\n\nuse crate::value::ValueRef;\nuse crate::{\n    decode::Decode,\n    encode::{Encode, IsNull},\n    error::BoxDynError,\n    type_info::DataType,\n    types::Type,\n    Sqlite, SqliteArgumentsBuffer, SqliteTypeInfo, SqliteValueRef,\n};\nuse chrono::FixedOffset;\nuse chrono::{\n    DateTime, Local, NaiveDate, NaiveDateTime, NaiveTime, Offset, SecondsFormat, TimeZone, Utc,\n};\n\nimpl<Tz: TimeZone> Type<Sqlite> for DateTime<Tz> {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Datetime)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        <NaiveDateTime as Type<Sqlite>>::compatible(ty)\n    }\n}\n\nimpl Type<Sqlite> for NaiveDateTime {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Datetime)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(\n            ty.0,\n            DataType::Datetime\n                | DataType::Text\n                | DataType::Integer\n                | DataType::Int4\n                | DataType::Float\n        )\n    }\n}\n\nimpl Type<Sqlite> for NaiveDate {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Date)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Date | DataType::Text)\n    }\n}\n\nimpl Type<Sqlite> for NaiveTime {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Time)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Time | DataType::Text)\n    }\n}\n\nimpl<Tz: TimeZone> Encode<'_, Sqlite> for DateTime<Tz>\nwhere\n    Tz::Offset: Display,\n{\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.to_rfc3339_opts(SecondsFormat::AutoSi, false), buf)\n    }\n}\n\nimpl Encode<'_, Sqlite> for NaiveDateTime {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.format(\"%F %T%.f\").to_string(), buf)\n    }\n}\n\nimpl Encode<'_, Sqlite> for NaiveDate {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.format(\"%F\").to_string(), buf)\n    }\n}\n\nimpl Encode<'_, Sqlite> for NaiveTime {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.format(\"%T%.f\").to_string(), buf)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for DateTime<Utc> {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(Utc.from_utc_datetime(&decode_datetime(value)?.naive_utc()))\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for DateTime<Local> {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(Local.from_utc_datetime(&decode_datetime(value)?.naive_utc()))\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for DateTime<FixedOffset> {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        decode_datetime(value)\n    }\n}\n\nfn decode_datetime(value: SqliteValueRef<'_>) -> Result<DateTime<FixedOffset>, BoxDynError> {\n    let dt = match value.type_info().0 {\n        DataType::Text => decode_datetime_from_text(value.text_borrowed()?),\n        DataType::Int4 | DataType::Integer => decode_datetime_from_int(value.int64()?),\n        DataType::Float => decode_datetime_from_float(value.double()?),\n\n        _ => None,\n    };\n\n    if let Some(dt) = dt {\n        Ok(dt)\n    } else {\n        Err(format!(\"invalid datetime: {}\", value.text_borrowed()?).into())\n    }\n}\n\nfn decode_datetime_from_text(value: &str) -> Option<DateTime<FixedOffset>> {\n    if let Ok(dt) = DateTime::parse_from_rfc3339(value) {\n        return Some(dt);\n    }\n\n    // Loop over common date time patterns, inspired by Diesel\n    // https://github.com/diesel-rs/diesel/blob/93ab183bcb06c69c0aee4a7557b6798fd52dd0d8/diesel/src/sqlite/types/date_and_time/chrono.rs#L56-L97\n    let sqlite_datetime_formats = &[\n        // Most likely format\n        \"%F %T%.f\",\n        // Other formats in order of appearance in docs\n        \"%F %R\",\n        \"%F %RZ\",\n        \"%F %R%:z\",\n        \"%F %T%.fZ\",\n        \"%F %T%.f%:z\",\n        \"%FT%R\",\n        \"%FT%RZ\",\n        \"%FT%R%:z\",\n        \"%FT%T%.f\",\n        \"%FT%T%.fZ\",\n        \"%FT%T%.f%:z\",\n    ];\n\n    for format in sqlite_datetime_formats {\n        if let Ok(dt) = DateTime::parse_from_str(value, format) {\n            return Some(dt);\n        }\n\n        if let Ok(dt) = NaiveDateTime::parse_from_str(value, format) {\n            return Some(Utc.fix().from_utc_datetime(&dt));\n        }\n    }\n\n    None\n}\n\nfn decode_datetime_from_int(value: i64) -> Option<DateTime<FixedOffset>> {\n    Utc.fix().timestamp_opt(value, 0).single()\n}\n\nfn decode_datetime_from_float(value: f64) -> Option<DateTime<FixedOffset>> {\n    let epoch_in_julian_days = 2_440_587.5;\n    let seconds_in_day = 86400.0;\n    let timestamp = (value - epoch_in_julian_days) * seconds_in_day;\n\n    if !timestamp.is_finite() {\n        return None;\n    }\n\n    // We don't really have a choice but to do lossy casts for this conversion\n    // We checked above if the value is infinite or NaN which could otherwise cause problems\n    #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]\n    {\n        let seconds = timestamp.trunc() as i64;\n        let nanos = (timestamp.fract() * 1E9).abs() as u32;\n\n        Utc.fix().timestamp_opt(seconds, nanos).single()\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for NaiveDateTime {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(decode_datetime(value)?.naive_local())\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for NaiveDate {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(NaiveDate::parse_from_str(value.text_borrowed()?, \"%F\")?)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for NaiveTime {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        let value = value.text_borrowed()?;\n\n        // Loop over common time patterns, inspired by Diesel\n        // https://github.com/diesel-rs/diesel/blob/93ab183bcb06c69c0aee4a7557b6798fd52dd0d8/diesel/src/sqlite/types/date_and_time/chrono.rs#L29-L47\n        #[rustfmt::skip] // don't like how rustfmt mangles the comments\n        let sqlite_time_formats = &[\n            // Most likely format\n            \"%T.f\", \"%T%.f\",\n            // Other formats in order of appearance in docs\n            \"%R\", \"%RZ\", \"%T%.fZ\", \"%R%:z\", \"%T%.f%:z\",\n        ];\n\n        for format in sqlite_time_formats {\n            if let Ok(dt) = NaiveTime::parse_from_str(value, format) {\n                return Ok(dt);\n            }\n        }\n\n        Err(format!(\"invalid time: {value}\").into())\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/float.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\n\nimpl Type<Sqlite> for f32 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Float)\n    }\n}\n\nimpl Encode<'_, Sqlite> for f32 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Double((*self).into()));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for f32 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<f32, BoxDynError> {\n        // Truncation is intentional\n        #[allow(clippy::cast_possible_truncation)]\n        Ok(value.double()? as f32)\n    }\n}\n\nimpl Type<Sqlite> for f64 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Float)\n    }\n}\n\nimpl Encode<'_, Sqlite> for f64 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Double(*self));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for f64 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<f64, BoxDynError> {\n        Ok(value.double()?)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/int.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\n\nimpl Type<Sqlite> for i8 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Int4)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for i8 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int(*self as i32));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for i8 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        // NOTE: using `sqlite3_value_int64()` here because `sqlite3_value_int()` silently truncates\n        // which leads to bugs, e.g.:\n        // https://github.com/launchbadge/sqlx/issues/3179\n        // Similar bug in Postgres: https://github.com/launchbadge/sqlx/issues/3161\n        Ok(value.int64()?.try_into()?)\n    }\n}\n\nimpl Type<Sqlite> for i16 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Int4)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for i16 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int(*self as i32));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for i16 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.int64()?.try_into()?)\n    }\n}\n\nimpl Type<Sqlite> for i32 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Int4)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for i32 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int(*self));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for i32 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.int64()?.try_into()?)\n    }\n}\n\nimpl Type<Sqlite> for i64 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Integer)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for i64 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int64(*self));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for i64 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.int64()?)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/json.rs",
    "content": "use serde::{Deserialize, Serialize};\n\nuse crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::types::{Json, Type};\nuse crate::{type_info::DataType, Sqlite, SqliteTypeInfo, SqliteValueRef};\n\nimpl<T> Type<Sqlite> for Json<T> {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Text)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        <&str as Type<Sqlite>>::compatible(ty)\n    }\n}\n\nimpl<T> Encode<'_, Sqlite> for Json<T>\nwhere\n    T: Serialize,\n{\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.encode_to_string()?, buf)\n    }\n}\n\nimpl<'r, T> Decode<'r, Sqlite> for Json<T>\nwhere\n    T: 'r + Deserialize<'r>,\n{\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        // Saves a pass over the data by making `serde_json` check UTF-8.\n        Self::decode_from_bytes(Decode::<Sqlite>::decode(value)?)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/mod.rs",
    "content": "//! Conversions between Rust and **SQLite** types.\n//!\n//! # Types\n//!\n//! | Rust type                             | SQLite type(s)                                       |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `bool`                                | BOOLEAN                                              |\n//! | `i8`                                  | INTEGER                                              |\n//! | `i16`                                 | INTEGER                                              |\n//! | `i32`                                 | INTEGER, INT4                                        |\n//! | `i64`                                 | BIGINT, INT8                                         |\n//! | `u8`                                  | INTEGER                                              |\n//! | `u16`                                 | INTEGER                                              |\n//! | `u32`                                 | INTEGER                                              |\n//! | `u64`                                 | INTEGER (Decode only; see note)                      |\n//! | `f32`                                 | REAL                                                 |\n//! | `f64`                                 | REAL                                                 |\n//! | `&str`, [`String`]                    | TEXT                                                 |\n//! | `&[u8]`, `Vec<u8>`                    | BLOB                                                 |\n//!\n//! #### Note: Unsigned Integers\n//! Decoding of unsigned integer types simply performs a checked conversion\n//! to ensure that overflow does not occur.\n//!\n//! Encoding of the unsigned integer types `u8`, `u16` and `u32` is implemented by zero-extending to\n//! the next-larger signed type. So `u8` becomes `i16`, `u16` becomes `i32`, and `u32` becomes `i64`\n//! while still retaining their semantic values.\n//!\n//! SQLite stores integers in a variable-width encoding and always handles them in memory as 64-bit\n//! signed values, so no space is wasted by this implicit widening.\n//!\n//! However, there is no corresponding larger type for `u64` in SQLite\n//! (it would require a native 16-byte integer, i.e. the equivalent of `i128`),\n//! and so encoding is not supported for this type.\n//!\n//! Bit-casting `u64` to `i64`, or storing it as `REAL`, `BLOB` or `TEXT`,\n//! would change the semantics of the value in SQL and so violates the principle of least surprise.\n//!\n//! ### [`chrono`](https://crates.io/crates/chrono)\n//!\n//! Requires the `chrono` Cargo feature flag.\n//!\n//! | Rust type                             | Sqlite type(s)                                       |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `chrono::NaiveDateTime`               | DATETIME (TEXT, INTEGER, REAL)                       |\n//! | `chrono::DateTime<Utc>`               | DATETIME (TEXT, INTEGER, REAL)                       |\n//! | `chrono::DateTime<Local>`             | DATETIME (TEXT, INTEGER, REAL)                       |\n//! | `chrono::DateTime<FixedOffset>`       | DATETIME (TEXT, INTEGER, REAL)                       |\n//! | `chrono::NaiveDate`                   | DATE (TEXT only)                                     |\n//! | `chrono::NaiveTime`                   | TIME (TEXT only)                                     |\n//!\n//! ##### NOTE: `DATETIME` conversions\n//! SQLite may represent `DATETIME` values as one of three types: `TEXT`, `REAL`, or `INTEGER`.\n//! Which one is used is entirely up to you and how you store timestamps in your database.\n//!\n//! The deserialization for `NaiveDateTime`, `DateTime<Utc>` and `DateTime<Local>` infer the date\n//! format from the type of the value they're being decoded from:\n//!\n//! * If `TEXT`, the format is assumed to be an ISO-8601 compatible datetime string.\n//!   A number of possible formats are tried; see `sqlx-sqlite/src/types/chrono.rs` for the current\n//!   set of formats.\n//! * If `INTEGER`, it is expected to be the number of seconds since January 1, 1970 00:00 UTC,\n//!   as if returned from the `unixepoch()` function (without the `subsec` modifier).\n//! * If `REAL`, it is expected to be the (possibly fractional) number of days since the Julian epoch,\n//!   November 24, 4714 BCE 12:00 UTC, as if returned from the `julianday()` function.\n//!\n//! These types will always encode to a datetime string, either\n//! with a timezone offset (`DateTime<Tz>` for any `Tz: TimeZone`) or without (`NaiveDateTime`).\n//!\n//! ##### NOTE: `CURRENT_TIMESTAMP` and comparison/interoperability of `DATETIME` values\n//! As stated previously, `DateTime<Tz>` always encodes to a date-time string\n//! _with_ a timezone offset,\n//! in [RFC 3339 format][::chrono::DateTime::to_rfc3339_opts] (with `use_z: false`).\n//!\n//! However, most of SQLite's datetime functions\n//! (including `datetime()` and `DEFAULT CURRENT_TIMESTAMP`)\n//! do not use this format. They instead use `YYYY-MM-DD HH:MM:SS.SSSS` without a timezone offset.\n//!\n//! This may cause problems with interoperability with other applications, and especially\n//! when comparing datetime values, which compares the actual string values lexicographically.\n//!\n//! Date-time strings in the SQLite format will generally _not_ compare consistently\n//! with date-time strings in the RFC 3339 format.\n//!\n//! We recommend that you decide up-front whether `DATETIME` values should be stored\n//! with explicit time zones or not, and use the corresponding type\n//! (and its corresponding offset, if applicable) _consistently_ throughout your\n//! application:\n//!\n//! * RFC 3339 format: `DateTime<Tz>` (e.g. `DateTime<Utc>`, `DateTime<Local>`, `DateTime<FixedOffset>`)\n//!   * Changing or mixing and matching offsets may break comparisons with existing timestamps.\n//!   * `DateTime<Local>` is **not recommended** for portable applications.\n//!   * `DateTime<FixedOffset>` is only recommended if the offset is **constant**.\n//! * SQLite format: `NaiveDateTime`\n//!\n//! Note that non-constant offsets may still cause issues when comparing timestamps,\n//! as the comparison operators are not timezone-aware.\n//!\n//! ### [`time`](https://crates.io/crates/time)\n//!\n//! Requires the `time` Cargo feature flag.\n//!\n//! | Rust type                             | Sqlite type(s)                                       |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `time::PrimitiveDateTime`             | DATETIME (TEXT, INTEGER)                             |\n//! | `time::OffsetDateTime`                | DATETIME (TEXT, INTEGER)                             |\n//! | `time::Date`                          | DATE (TEXT only)                                     |\n//! | `time::Time`                          | TIME (TEXT only)                                     |\n//!\n//! ##### NOTE: `DATETIME` conversions\n//! The behavior here is identical to the corresponding `chrono` types, minus the support for `REAL`\n//! values as Julian days (it's just not implemented).\n//!\n//! `PrimitiveDateTime` and `OffsetDateTime` will always encode to a datetime string, either\n//! with a timezone offset (`OffsetDateTime`) or without (`PrimitiveDateTime`).\n//!\n//! ##### NOTE: `CURRENT_TIMESTAMP` and comparison/interoperability of `DATETIME` values\n//! As stated previously, `OffsetDateTime` always encodes to a datetime string _with_ a timezone offset,\n//! in [RFC 3339 format][::time::format_description::well_known::Rfc3339] (using `Z` for UTC offsets).\n//!\n//! However, most of SQLite's datetime functions\n//! (including `datetime()` and `DEFAULT CURRENT_TIMESTAMP`)\n//! do not use this format. They instead use `YYYY-MM-DD HH:MM:SS.SSSS` without a timezone offset.\n//!\n//! This may cause problems with interoperability with other applications, and especially\n//! when comparing datetime values, which compares the actual string values lexicographically.\n//!\n//! Date-time strings in the SQLite format will generally _not_ compare consistently\n//! with date-time strings in the RFC 3339 format.\n//!\n//! We recommend that you decide up-front whether `DATETIME` values should be stored\n//! with explicit time zones or not, and use the corresponding type\n//! (and its corresponding offset, if applicable) _consistently_ throughout your\n//! application:\n//!\n//! * RFC 3339 format: `OffsetDateTime` with a **constant** offset.\n//!   * Changing or mixing and matching offsets may break comparisons with existing timestamps.\n//!   * `OffsetDateTime::now_local()` is **not recommended** for portable applications.\n//!   * Non-UTC offsets are only recommended if the offset is **constant**.\n//! * SQLite format: `PrimitiveDateTime`\n//!\n//! Note that non-constant offsets may still cause issues when comparing timestamps,\n//! as the comparison operators are not timezone-aware.\n//!\n//! ### [`uuid`](https://crates.io/crates/uuid)\n//!\n//! Requires the `uuid` Cargo feature flag.\n//!\n//! | Rust type                             | Sqlite type(s)                                       |\n//! |---------------------------------------|------------------------------------------------------|\n//! | `uuid::Uuid`                          | BLOB, TEXT                                           |\n//! | `uuid::fmt::Hyphenated`               | TEXT                                                 |\n//! | `uuid::fmt::Simple`                   | TEXT                                                 |\n//!\n//! ### [`json`](https://crates.io/crates/serde_json)\n//!\n//! Requires the `json` Cargo feature flag.\n//!\n//! | Rust type                             | Sqlite type(s)                                       |\n//! |---------------------------------------|------------------------------------------------------|\n//! | [`Json<T>`]                           | TEXT                                                 |\n//! | `serde_json::JsonValue`               | TEXT                                                 |\n//! | `&serde_json::value::RawValue`        | TEXT                                                 |\n//!\n//! # Nullable\n//!\n//! In addition, `Option<T>` is supported where `T` implements `Type`. An `Option<T>` represents\n//! a potentially `NULL` value from SQLite.\n//!\n//! # Non-feature: `NUMERIC` / `rust_decimal` / `bigdecimal` Support\n//! Support for mapping `rust_decimal::Decimal` and `bigdecimal::BigDecimal` to SQLite has been\n//! deliberately omitted because SQLite does not have native support for high-\n//! or arbitrary-precision decimal arithmetic, and to pretend so otherwise would be a\n//! significant misstep in API design.\n//!\n//! The in-tree [`decimal.c`] extension is unfortunately not included in the [amalgamation],\n//! which is used to build the bundled version of SQLite3 for `libsqlite3-sys` (which we have\n//! enabled by default for the simpler setup experience), otherwise we could support that.\n//!\n//! The `NUMERIC` type affinity, while seemingly designed for storing decimal values,\n//! stores non-integer real numbers as double-precision IEEE-754 floating point,\n//! i.e. `REAL` in SQLite, `f64` in Rust, `double` in C/C++, etc.\n//!\n//! [Datatypes in SQLite: Type Affinity][type-affinity] (accessed 2023/11/20):\n//!\n//! > A column with NUMERIC affinity may contain values using all five storage classes.\n//! > When text data is inserted into a NUMERIC column, the storage class of the text is converted to\n//! > INTEGER or REAL (in order of preference) if the text is a well-formed integer or real literal,\n//! > respectively. If the TEXT value is a well-formed integer literal that is too large to fit in a\n//! > 64-bit signed integer, it is converted to REAL. For conversions between TEXT and REAL storage\n//! > classes, only the first 15 significant decimal digits of the number are preserved.\n//!\n//! With the SQLite3 interactive CLI, we can see that a higher-precision value\n//! (20 digits in this case) is rounded off:\n//!\n//! ```text\n//! sqlite> CREATE TABLE foo(bar NUMERIC);\n//! sqlite> INSERT INTO foo(bar) VALUES('1.2345678901234567890');\n//! sqlite> SELECT * FROM foo;\n//! 1.23456789012346\n//! ```\n//!\n//! It appears the `TEXT` storage class is only used if the value contains invalid characters\n//! or extra whitespace.\n//!\n//! Thus, the `NUMERIC` type affinity is **unsuitable** for storage of high-precision decimal values\n//! and should be **avoided at all costs**.\n//!\n//! Support for `rust_decimal` and `bigdecimal` would only be a trap because users will naturally\n//! want to use the `NUMERIC` type affinity, and might otherwise encounter serious bugs caused by\n//! rounding errors that they were deliberately avoiding when they chose an arbitrary-precision type\n//! over a floating-point type in the first place.\n//!\n//! Instead, you should only use a type affinity that SQLite will not attempt to convert implicitly,\n//! such as `TEXT` or `BLOB`, and map values to/from SQLite as strings. You can do this easily\n//! using [the `Text` adapter].\n//!\n//!\n//! [`decimal.c`]: https://www.sqlite.org/floatingpoint.html#the_decimal_c_extension\n//! [amalgamation]: https://www.sqlite.org/amalgamation.html\n//! [type-affinity]: https://www.sqlite.org/datatype3.html#type_affinity\n//! [the `Text` adapter]: Text\n\npub(crate) use sqlx_core::types::*;\n\nmod bool;\nmod bytes;\n#[cfg(feature = \"chrono\")]\nmod chrono;\nmod float;\nmod int;\n#[cfg(feature = \"json\")]\nmod json;\nmod str;\nmod text;\n#[cfg(feature = \"time\")]\nmod time;\nmod uint;\n#[cfg(feature = \"uuid\")]\nmod uuid;\n"
  },
  {
    "path": "sqlx-sqlite/src/types/str.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\nuse sqlx_core::database::Database;\nuse std::borrow::Cow;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\nimpl Type<Sqlite> for str {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Text)\n    }\n}\n\nimpl Encode<'_, Sqlite> for &'_ str {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.to_string())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for &'r str {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.text_borrowed()?)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Box<str> {\n    fn encode(self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::TextSlice(Arc::from(self)));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.to_string())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Type<Sqlite> for String {\n    fn type_info() -> SqliteTypeInfo {\n        <&str as Type<Sqlite>>::type_info()\n    }\n}\n\nimpl Encode<'_, Sqlite> for String {\n    fn encode(self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self)));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.clone())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for String {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.text_owned()?)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Cow<'_, str> {\n    fn encode(self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.into())));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.to_string())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Arc<str> {\n    fn encode(self, args: &mut <Sqlite as Database>::ArgumentBuffer) -> Result<IsNull, BoxDynError>\n    where\n        Self: Sized,\n    {\n        args.push(SqliteArgumentValue::TextSlice(self));\n\n        Ok(IsNull::No)\n    }\n\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        <String as Encode<'_, Sqlite>>::encode(self.to_string(), args)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Rc<str> {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        <String as Encode<'_, Sqlite>>::encode(self.to_string(), args)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/text.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::{Sqlite, SqliteTypeInfo, SqliteValueRef};\nuse sqlx_core::decode::Decode;\nuse sqlx_core::encode::{Encode, IsNull};\nuse sqlx_core::error::BoxDynError;\nuse sqlx_core::types::{Text, Type};\nuse std::fmt::Display;\nuse std::str::FromStr;\n\nimpl<T> Type<Sqlite> for Text<T> {\n    fn type_info() -> SqliteTypeInfo {\n        <String as Type<Sqlite>>::type_info()\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        <String as Type<Sqlite>>::compatible(ty)\n    }\n}\n\nimpl<T> Encode<'_, Sqlite> for Text<T>\nwhere\n    T: Display,\n{\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.0.to_string(), buf)\n    }\n}\n\nimpl<'r, T> Decode<'r, Sqlite> for Text<T>\nwhere\n    T: FromStr,\n    BoxDynError: From<<T as FromStr>::Err>,\n{\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(Self(value.with_temp_text(|text| text.parse::<T>())??))\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/time.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::value::ValueRef;\nuse crate::{\n    decode::Decode,\n    encode::{Encode, IsNull},\n    error::BoxDynError,\n    type_info::DataType,\n    types::Type,\n    Sqlite, SqliteTypeInfo, SqliteValueRef,\n};\nuse time::format_description::{well_known::Rfc3339, BorrowedFormatItem};\nuse time::macros::format_description as fd;\nuse time::{Date, OffsetDateTime, PrimitiveDateTime, Time};\n\nimpl Type<Sqlite> for OffsetDateTime {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Datetime)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        <PrimitiveDateTime as Type<Sqlite>>::compatible(ty)\n    }\n}\n\nimpl Type<Sqlite> for PrimitiveDateTime {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Datetime)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(\n            ty.0,\n            DataType::Datetime | DataType::Text | DataType::Integer | DataType::Int4\n        )\n    }\n}\n\nimpl Type<Sqlite> for Date {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Date)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Date | DataType::Text)\n    }\n}\n\nimpl Type<Sqlite> for Time {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Time)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Time | DataType::Text)\n    }\n}\n\nimpl Encode<'_, Sqlite> for OffsetDateTime {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        Encode::<Sqlite>::encode(self.format(&Rfc3339)?, buf)\n    }\n}\n\nimpl Encode<'_, Sqlite> for PrimitiveDateTime {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        let format = fd!(\"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]\");\n        Encode::<Sqlite>::encode(self.format(&format)?, buf)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Date {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        let format = fd!(\"[year]-[month]-[day]\");\n        Encode::<Sqlite>::encode(self.format(&format)?, buf)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Time {\n    fn encode_by_ref(&self, buf: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        let format = fd!(\"[hour]:[minute]:[second].[subsecond]\");\n        Encode::<Sqlite>::encode(self.format(&format)?, buf)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for OffsetDateTime {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        decode_offset_datetime(value)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for PrimitiveDateTime {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        decode_datetime(value)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for Date {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(Date::parse(\n            value.text_borrowed()?,\n            &fd!(\"[year]-[month]-[day]\"),\n        )?)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for Time {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        let value = value.text_borrowed()?;\n\n        let sqlite_time_formats = &[\n            fd!(\"[hour]:[minute]:[second].[subsecond]\"),\n            fd!(\"[hour]:[minute]:[second]\"),\n            fd!(\"[hour]:[minute]\"),\n        ];\n\n        for format in sqlite_time_formats {\n            if let Ok(dt) = Time::parse(value, &format) {\n                return Ok(dt);\n            }\n        }\n\n        Err(format!(\"invalid time: {value}\").into())\n    }\n}\n\nfn decode_offset_datetime(value: SqliteValueRef<'_>) -> Result<OffsetDateTime, BoxDynError> {\n    let dt = match value.type_info().0 {\n        DataType::Text => decode_offset_datetime_from_text(value.text_borrowed()?),\n        DataType::Int4 | DataType::Integer => {\n            Some(OffsetDateTime::from_unix_timestamp(value.int64()?)?)\n        }\n\n        _ => None,\n    };\n\n    if let Some(dt) = dt {\n        Ok(dt)\n    } else {\n        Err(format!(\"invalid offset datetime: {}\", value.text_borrowed()?).into())\n    }\n}\n\nfn decode_offset_datetime_from_text(value: &str) -> Option<OffsetDateTime> {\n    if let Ok(dt) = OffsetDateTime::parse(value, &Rfc3339) {\n        return Some(dt);\n    }\n\n    if let Ok(dt) = OffsetDateTime::parse(value, formats::OFFSET_DATE_TIME) {\n        return Some(dt);\n    }\n\n    if let Some(dt) = decode_datetime_from_text(value) {\n        return Some(dt.assume_utc());\n    }\n\n    None\n}\n\nfn decode_datetime(value: SqliteValueRef<'_>) -> Result<PrimitiveDateTime, BoxDynError> {\n    let dt = match value.type_info().0 {\n        DataType::Text => decode_datetime_from_text(value.text_borrowed()?),\n        DataType::Int4 | DataType::Integer => {\n            let parsed = OffsetDateTime::from_unix_timestamp(value.int64()?).unwrap();\n            Some(PrimitiveDateTime::new(parsed.date(), parsed.time()))\n        }\n\n        _ => None,\n    };\n\n    if let Some(dt) = dt {\n        Ok(dt)\n    } else {\n        Err(format!(\"invalid datetime: {}\", value.text_borrowed()?).into())\n    }\n}\n\nfn decode_datetime_from_text(value: &str) -> Option<PrimitiveDateTime> {\n    let default_format = fd!(\"[year]-[month]-[day] [hour]:[minute]:[second].[subsecond]\");\n    if let Ok(dt) = PrimitiveDateTime::parse(value, &default_format) {\n        return Some(dt);\n    }\n\n    let formats = [\n        BorrowedFormatItem::Compound(formats::PRIMITIVE_DATE_TIME_SPACE_SEPARATED),\n        BorrowedFormatItem::Compound(formats::PRIMITIVE_DATE_TIME_T_SEPARATED),\n    ];\n\n    if let Ok(dt) = PrimitiveDateTime::parse(value, &BorrowedFormatItem::First(&formats)) {\n        return Some(dt);\n    }\n\n    None\n}\n\nmod formats {\n    use time::format_description::BorrowedFormatItem::{Component, Literal, Optional};\n    use time::format_description::{modifier, BorrowedFormatItem, Component::*};\n\n    const YEAR: BorrowedFormatItem<'_> = Component(Year({\n        let mut value = modifier::Year::default();\n        value.padding = modifier::Padding::Zero;\n        value.repr = modifier::YearRepr::Full;\n        value.iso_week_based = false;\n        value.sign_is_mandatory = false;\n        value\n    }));\n\n    const MONTH: BorrowedFormatItem<'_> = Component(Month({\n        let mut value = modifier::Month::default();\n        value.padding = modifier::Padding::Zero;\n        value.repr = modifier::MonthRepr::Numerical;\n        value.case_sensitive = true;\n        value\n    }));\n\n    const DAY: BorrowedFormatItem<'_> = Component(Day({\n        let mut value = modifier::Day::default();\n        value.padding = modifier::Padding::Zero;\n        value\n    }));\n\n    const HOUR: BorrowedFormatItem<'_> = Component(Hour({\n        let mut value = modifier::Hour::default();\n        value.padding = modifier::Padding::Zero;\n        value.is_12_hour_clock = false;\n        value\n    }));\n\n    const MINUTE: BorrowedFormatItem<'_> = Component(Minute({\n        let mut value = modifier::Minute::default();\n        value.padding = modifier::Padding::Zero;\n        value\n    }));\n\n    const SECOND: BorrowedFormatItem<'_> = Component(Second({\n        let mut value = modifier::Second::default();\n        value.padding = modifier::Padding::Zero;\n        value\n    }));\n\n    const SUBSECOND: BorrowedFormatItem<'_> = Component(Subsecond({\n        let mut value = modifier::Subsecond::default();\n        value.digits = modifier::SubsecondDigits::OneOrMore;\n        value\n    }));\n\n    const OFFSET_HOUR: BorrowedFormatItem<'_> = Component(OffsetHour({\n        let mut value = modifier::OffsetHour::default();\n        value.sign_is_mandatory = true;\n        value.padding = modifier::Padding::Zero;\n        value\n    }));\n\n    const OFFSET_MINUTE: BorrowedFormatItem<'_> = Component(OffsetMinute({\n        let mut value = modifier::OffsetMinute::default();\n        value.padding = modifier::Padding::Zero;\n        value\n    }));\n\n    pub(super) const OFFSET_DATE_TIME: &[BorrowedFormatItem<'_>] = {\n        &[\n            YEAR,\n            Literal(b\"-\"),\n            MONTH,\n            Literal(b\"-\"),\n            DAY,\n            Optional(&Literal(b\" \")),\n            Optional(&Literal(b\"T\")),\n            HOUR,\n            Literal(b\":\"),\n            MINUTE,\n            Optional(&Literal(b\":\")),\n            Optional(&SECOND),\n            Optional(&Literal(b\".\")),\n            Optional(&SUBSECOND),\n            Optional(&OFFSET_HOUR),\n            Optional(&Literal(b\":\")),\n            Optional(&OFFSET_MINUTE),\n        ]\n    };\n\n    pub(super) const PRIMITIVE_DATE_TIME_SPACE_SEPARATED: &[BorrowedFormatItem<'_>] = {\n        &[\n            YEAR,\n            Literal(b\"-\"),\n            MONTH,\n            Literal(b\"-\"),\n            DAY,\n            Literal(b\" \"),\n            HOUR,\n            Literal(b\":\"),\n            MINUTE,\n            Optional(&Literal(b\":\")),\n            Optional(&SECOND),\n            Optional(&Literal(b\".\")),\n            Optional(&SUBSECOND),\n            Optional(&Literal(b\"Z\")),\n        ]\n    };\n\n    pub(super) const PRIMITIVE_DATE_TIME_T_SEPARATED: &[BorrowedFormatItem<'_>] = {\n        &[\n            YEAR,\n            Literal(b\"-\"),\n            MONTH,\n            Literal(b\"-\"),\n            DAY,\n            Literal(b\"T\"),\n            HOUR,\n            Literal(b\":\"),\n            MINUTE,\n            Optional(&Literal(b\":\")),\n            Optional(&SECOND),\n            Optional(&Literal(b\".\")),\n            Optional(&SUBSECOND),\n            Optional(&Literal(b\"Z\")),\n        ]\n    };\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/uint.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\n\nimpl Type<Sqlite> for u8 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Int4)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for u8 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int(*self as i32));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for u8 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        // NOTE: using `sqlite3_value_int64()` here because `sqlite3_value_int()` silently truncates\n        // which leads to bugs, e.g.:\n        // https://github.com/launchbadge/sqlx/issues/3179\n        // Similar bug in Postgres: https://github.com/launchbadge/sqlx/issues/3161\n        Ok(value.int64()?.try_into()?)\n    }\n}\n\nimpl Type<Sqlite> for u16 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Int4)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for u16 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int(*self as i32));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for u16 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.int64()?.try_into()?)\n    }\n}\n\nimpl Type<Sqlite> for u32 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Integer)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl Encode<'_, Sqlite> for u32 {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Int64(*self as i64));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for u32 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.int64()?.try_into()?)\n    }\n}\n\nimpl Type<Sqlite> for u64 {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Integer)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Int4 | DataType::Integer)\n    }\n}\n\nimpl<'r> Decode<'r, Sqlite> for u64 {\n    fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {\n        Ok(value.int64()?.try_into()?)\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/types/uuid.rs",
    "content": "use crate::arguments::SqliteArgumentsBuffer;\nuse crate::decode::Decode;\nuse crate::encode::{Encode, IsNull};\nuse crate::error::BoxDynError;\nuse crate::type_info::DataType;\nuse crate::types::Type;\nuse crate::{Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};\nuse std::sync::Arc;\nuse uuid::{\n    fmt::{Hyphenated, Simple},\n    Uuid,\n};\n\nimpl Type<Sqlite> for Uuid {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Blob)\n    }\n\n    fn compatible(ty: &SqliteTypeInfo) -> bool {\n        matches!(ty.0, DataType::Blob | DataType::Text)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Uuid {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Blob(Arc::new(\n            self.as_bytes().to_vec(),\n        )));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Sqlite> for Uuid {\n    fn decode(value: SqliteValueRef<'_>) -> Result<Self, BoxDynError> {\n        // construct a Uuid from the returned bytes\n        Uuid::from_slice(value.blob_borrowed()).map_err(Into::into)\n    }\n}\n\nimpl Type<Sqlite> for Hyphenated {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Text)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Hyphenated {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.to_string())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Sqlite> for Hyphenated {\n    fn decode(value: SqliteValueRef<'_>) -> Result<Self, BoxDynError> {\n        let uuid: Result<Uuid, BoxDynError> =\n            Uuid::parse_str(&value.text_borrowed().map(ToOwned::to_owned)?).map_err(Into::into);\n\n        Ok(uuid?.hyphenated())\n    }\n}\n\nimpl Type<Sqlite> for Simple {\n    fn type_info() -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::Text)\n    }\n}\n\nimpl Encode<'_, Sqlite> for Simple {\n    fn encode_by_ref(&self, args: &mut SqliteArgumentsBuffer) -> Result<IsNull, BoxDynError> {\n        args.push(SqliteArgumentValue::Text(Arc::new(self.to_string())));\n\n        Ok(IsNull::No)\n    }\n}\n\nimpl Decode<'_, Sqlite> for Simple {\n    fn decode(value: SqliteValueRef<'_>) -> Result<Self, BoxDynError> {\n        let uuid: Result<Uuid, BoxDynError> =\n            Uuid::parse_str(&value.text_borrowed().map(ToOwned::to_owned)?).map_err(Into::into);\n\n        Ok(uuid?.simple())\n    }\n}\n"
  },
  {
    "path": "sqlx-sqlite/src/value.rs",
    "content": "use std::borrow::Cow;\nuse std::cell::OnceCell;\nuse std::ptr::NonNull;\nuse std::slice;\nuse std::str;\n\nuse libsqlite3_sys::{\n    sqlite3_value, sqlite3_value_blob, sqlite3_value_bytes, sqlite3_value_double,\n    sqlite3_value_dup, sqlite3_value_free, sqlite3_value_int64, sqlite3_value_type,\n};\nuse sqlx_core::type_info::TypeInfo;\npub(crate) use sqlx_core::value::{Value, ValueRef};\n\nuse crate::type_info::DataType;\nuse crate::{Sqlite, SqliteError, SqliteTypeInfo};\n\n/// An owned handle to a [`sqlite3_value`].\n///\n/// # Note: Decoding is Stateful\n/// The [`sqlite3_value` interface][value-methods] reserves the right to be stateful:\n///\n/// > Other interfaces might change the datatype for an sqlite3_value object.\n/// > For example, if the datatype is initially SQLITE_INTEGER and sqlite3_value_text(V) is called\n/// > to extract a text value for that integer, then subsequent calls to sqlite3_value_type(V)\n/// > might return SQLITE_TEXT. Whether or not a persistent internal datatype conversion occurs is\n/// > undefined and may change from one release of SQLite to the next.\n///\n/// Thus, this type is `!Sync` and [`SqliteValueRef`] is `!Send` and `!Sync` to prevent data races.\n///\n/// Additionally, this statefulness means that the return values of `sqlite3_value_bytes()` and\n/// `sqlite3_value_blob()` could be invalidated by later calls to other `sqlite3_value*` methods.\n///\n/// To prevent undefined behavior from accessing dangling pointers, this type (and any\n/// [`SqliteValueRef`] instances created from it) remembers when it was used to decode a\n/// borrowed `&[u8]` or `&str` and returns an error if it is used to decode any other type.\n///\n/// To bypass this error, you must prove that no outstanding borrows exist.\n///\n/// This may be done in one of a few ways:\n/// * If you hold mutable access, call [`Self::reset_borrow()`] which resets the borrowed state.\n/// * If you have an immutable reference, call [`Self::clone()`] to get a new instance\n///   with no outstanding borrows.\n/// * If you hold a [`SqliteValueRef`], call [`SqliteValueRef::to_owned()`]\n///   to get a new `SqliteValue` with no outstanding borrows.\n///\n/// This is *only* necessary if using the same `SqliteValue` or [`SqliteValueRef`] to decode\n/// multiple different types. The vast majority of use-cases employing once-through decoding\n/// should not have to worry about this.\n///\n/// [`sqlite3_value`]: https://www.sqlite.org/c3ref/value.html\n/// [value-methods]: https://www.sqlite.org/c3ref/value_blob.html\npub struct SqliteValue(ValueHandle);\n\n/// A borrowed reference to a [`sqlite3_value`].\n///\n/// Semantically, this behaves as a reference to [`SqliteValue`].\n///\n/// # Note: Decoding is Stateful\n/// See [`SqliteValue`] for details.\npub struct SqliteValueRef<'r>(Cow<'r, ValueHandle>);\n\nimpl SqliteValue {\n    // SAFETY: The sqlite3_value must be non-null and SQLite must not free it. It will be freed on drop.\n    pub(crate) unsafe fn dup(\n        value: *mut sqlite3_value,\n        column_type: Option<SqliteTypeInfo>,\n    ) -> Self {\n        debug_assert!(!value.is_null());\n        let handle = ValueHandle::try_dup_of(value, column_type)\n            .expect(\"SQLite failed to allocate memory for duplicated value\");\n        Self(handle)\n    }\n\n    /// Prove that there are no outstanding borrows of this instance.\n    ///\n    /// Call this after decoding a borrowed `&[u8]` or `&str`\n    /// to reset the internal borrowed state and allow decoding of other types.\n    pub fn reset_borrow(&mut self) {\n        self.0.reset_blob_borrow();\n    }\n\n    /// Call [`sqlite3_value_dup()`] to create a new instance of this type.\n    ///\n    /// Returns an error if the call returns a null pointer, indicating that\n    /// SQLite was unable to allocate the additional memory required.\n    ///\n    /// Non-panicking version of [`Self::clone()`].\n    ///\n    /// [`sqlite3_value_dup()`]: https://www.sqlite.org/c3ref/value_dup.html\n    pub fn try_clone(&self) -> Result<Self, SqliteError> {\n        self.0.try_dup().map(Self)\n    }\n}\n\nimpl Clone for SqliteValue {\n    /// Call [`sqlite3_value_dup()`] to create a new instance of this type.\n    ///\n    /// # Panics\n    /// If [`sqlite3_value_dup()`] returns a null pointer, indicating an out-of-memory condition.\n    ///\n    /// See [`Self::try_clone()`] for a non-panicking version.\n    ///\n    /// [`sqlite3_value_dup()`]: https://www.sqlite.org/c3ref/value_dup.html\n    fn clone(&self) -> Self {\n        self.try_clone().expect(\"failed to clone `SqliteValue`\")\n    }\n}\n\nimpl Value for SqliteValue {\n    type Database = Sqlite;\n\n    fn as_ref(&self) -> SqliteValueRef<'_> {\n        SqliteValueRef::value(self)\n    }\n\n    fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {\n        Cow::Owned(self.0.type_info())\n    }\n\n    fn is_null(&self) -> bool {\n        self.0.is_null()\n    }\n}\n\nimpl<'r> SqliteValueRef<'r> {\n    /// Attempt to duplicate the internal `sqlite3_value` with [`sqlite3_value_dup()`].\n    ///\n    /// Returns an error if the call returns a null pointer, indicating that\n    /// SQLite was unable to allocate the additional memory required.\n    ///\n    /// Non-panicking version of [`Self::try_to_owned()`].\n    ///\n    /// [`sqlite3_value_dup()`]: https://www.sqlite.org/c3ref/value_dup.html\n    pub fn try_to_owned(&self) -> Result<SqliteValue, SqliteError> {\n        self.0.try_dup().map(SqliteValue)\n    }\n\n    pub(crate) fn value(value: &'r SqliteValue) -> Self {\n        Self(Cow::Borrowed(&value.0))\n    }\n\n    /// # Safety\n    /// The supplied sqlite3_value must not be null and SQLite must free it.\n    /// It will not be freed on drop.\n    /// The lifetime on this struct should tie it to whatever scope it's valid for before SQLite frees it.\n    #[allow(unused)]\n    pub(crate) unsafe fn borrowed(value: *mut sqlite3_value) -> Self {\n        debug_assert!(!value.is_null());\n        let handle = ValueHandle::temporary(NonNull::new_unchecked(value));\n        Self(Cow::Owned(handle))\n    }\n\n    // NOTE: `int()` is deliberately omitted because it will silently truncate a wider value,\n    // which is likely to cause bugs:\n    // https://github.com/launchbadge/sqlx/issues/3179\n    // (Similar bug in Postgres): https://github.com/launchbadge/sqlx/issues/3161\n    pub(super) fn int64(&self) -> Result<i64, BorrowedBlobError> {\n        self.0.int64()\n    }\n\n    pub(super) fn double(&self) -> Result<f64, BorrowedBlobError> {\n        self.0.double()\n    }\n\n    pub(super) fn blob_borrowed(&self) -> &'r [u8] {\n        // SAFETY: lifetime is matched to `'r`\n        unsafe { self.0.blob_borrowed() }\n    }\n\n    pub(super) fn with_temp_blob<R>(&self, op: impl FnOnce(&[u8]) -> R) -> R {\n        self.0.with_blob(op)\n    }\n\n    pub(super) fn blob_owned(&self) -> Vec<u8> {\n        self.with_temp_blob(|blob| blob.to_vec())\n    }\n\n    pub(super) fn text_borrowed(&self) -> Result<&'r str, str::Utf8Error> {\n        // SAFETY: lifetime is matched to `'r`\n        unsafe { self.0.text_borrowed() }\n    }\n\n    pub(super) fn with_temp_text<R>(\n        &self,\n        op: impl FnOnce(&str) -> R,\n    ) -> Result<R, str::Utf8Error> {\n        self.0.with_blob(|blob| str::from_utf8(blob).map(op))\n    }\n\n    pub(super) fn text_owned(&self) -> Result<String, str::Utf8Error> {\n        self.with_temp_text(|text| text.to_string())\n    }\n}\n\nimpl<'r> ValueRef<'r> for SqliteValueRef<'r> {\n    type Database = Sqlite;\n\n    /// Attempt to duplicate the internal `sqlite3_value` with [`sqlite3_value_dup()`].\n    ///\n    /// # Panics\n    /// If [`sqlite3_value_dup()`] returns a null pointer, indicating an out-of-memory condition.\n    ///\n    /// See [`Self::try_to_owned()`] for a non-panicking version.\n    ///\n    /// [`sqlite3_value_dup()`]: https://www.sqlite.org/c3ref/value_dup.html\n    fn to_owned(&self) -> SqliteValue {\n        SqliteValue(\n            self.0\n                .try_dup()\n                .expect(\"failed to convert SqliteValueRef to owned SqliteValue\"),\n        )\n    }\n\n    fn type_info(&self) -> Cow<'_, SqliteTypeInfo> {\n        Cow::Owned(self.0.type_info())\n    }\n\n    fn is_null(&self) -> bool {\n        self.0.is_null()\n    }\n}\n\npub(crate) struct ValueHandle {\n    value: NonNull<sqlite3_value>,\n    column_type: Option<SqliteTypeInfo>,\n    // Note: `std::cell` version\n    borrowed_blob: OnceCell<Blob>,\n    free_on_drop: bool,\n}\n\nstruct Blob {\n    ptr: *const u8,\n    len: usize,\n}\n\n#[derive(Debug, thiserror::Error)]\n#[error(\"given `SqliteValue` was previously decoded as BLOB or TEXT; `SqliteValue::reset_borrow()` must be called first\")]\npub(crate) struct BorrowedBlobError;\n\n// SAFE: only protected value objects are stored in SqliteValue\nunsafe impl Send for ValueHandle {}\n\n// SAFETY: the `sqlite3_value_*()` methods reserve the right to be stateful,\n// which means method calls aren't thread-safe without mutual exclusion.\n//\n// impl !Sync for ValueHandle {}\n\nimpl ValueHandle {\n    /// # Safety\n    /// The `sqlite3_value` must be valid and SQLite must not free it. It will be freed on drop.\n    unsafe fn try_dup_of(\n        value: *mut sqlite3_value,\n        column_type: Option<SqliteTypeInfo>,\n    ) -> Result<Self, SqliteError> {\n        // SAFETY: caller must ensure `value` is valid.\n        let value =\n            unsafe { NonNull::new(sqlite3_value_dup(value)).ok_or_else(SqliteError::nomem)? };\n\n        Ok(Self {\n            value,\n            column_type,\n            borrowed_blob: OnceCell::new(),\n            free_on_drop: true,\n        })\n    }\n\n    fn temporary(value: NonNull<sqlite3_value>) -> Self {\n        Self {\n            value,\n            column_type: None,\n            borrowed_blob: OnceCell::new(),\n            free_on_drop: false,\n        }\n    }\n\n    fn try_dup(&self) -> Result<Self, SqliteError> {\n        // SAFETY: `value` is initialized\n        unsafe { Self::try_dup_of(self.value.as_ptr(), self.column_type.clone()) }\n    }\n\n    fn value_type_info(&self) -> SqliteTypeInfo {\n        SqliteTypeInfo(DataType::from_code(unsafe {\n            sqlite3_value_type(self.value.as_ptr())\n        }))\n    }\n\n    fn type_info(&self) -> SqliteTypeInfo {\n        let value_type = self.value_type_info();\n\n        // Assume the actual value type is more accurate, if it's not NULL.\n        match &self.column_type {\n            Some(column_type) if value_type.is_null() => column_type.clone(),\n            _ => value_type,\n        }\n    }\n\n    fn int64(&self) -> Result<i64, BorrowedBlobError> {\n        // SAFETY: we have to be certain the caller isn't still holding a borrow from `.blob_borrowed()`\n        self.assert_blob_not_borrowed()?;\n\n        Ok(unsafe { sqlite3_value_int64(self.value.as_ptr()) })\n    }\n\n    fn double(&self) -> Result<f64, BorrowedBlobError> {\n        // SAFETY: we have to be certain the caller isn't still holding a borrow from `.blob_borrowed()`\n        self.assert_blob_not_borrowed()?;\n\n        Ok(unsafe { sqlite3_value_double(self.value.as_ptr()) })\n    }\n\n    fn is_null(&self) -> bool {\n        self.value_type_info().is_null()\n    }\n}\n\nimpl Clone for ValueHandle {\n    fn clone(&self) -> Self {\n        self.try_dup().unwrap()\n    }\n}\n\nimpl Drop for ValueHandle {\n    fn drop(&mut self) {\n        if self.free_on_drop {\n            unsafe {\n                sqlite3_value_free(self.value.as_ptr());\n            }\n        }\n    }\n}\n\nimpl ValueHandle {\n    fn assert_blob_not_borrowed(&self) -> Result<(), BorrowedBlobError> {\n        if self.borrowed_blob.get().is_none() {\n            Ok(())\n        } else {\n            Err(BorrowedBlobError)\n        }\n    }\n\n    fn reset_blob_borrow(&mut self) {\n        self.borrowed_blob.take();\n    }\n\n    fn get_blob(&self) -> Option<Blob> {\n        if let Some(blob) = self.borrowed_blob.get() {\n            return Some(Blob { ..*blob });\n        }\n\n        // SAFETY: calling `sqlite3_value_bytes` from multiple threads at once is a data race.\n        let len = unsafe { sqlite3_value_bytes(self.value.as_ptr()) };\n\n        // This likely means UB in SQLite itself or our usage of it;\n        // signed integer overflow is UB in the C standard.\n        let len = usize::try_from(len).unwrap_or_else(|_| {\n            panic!(\"sqlite3_value_bytes() returned value out of range for usize: {len}\")\n        });\n\n        if len == 0 {\n            // empty blobs are NULL\n            return None;\n        }\n\n        let ptr = unsafe { sqlite3_value_blob(self.value.as_ptr()) } as *const u8;\n        debug_assert!(!ptr.is_null());\n\n        Some(Blob { ptr, len })\n    }\n\n    fn with_blob<R>(&self, with_blob: impl FnOnce(&[u8]) -> R) -> R {\n        let Some(blob) = self.get_blob() else {\n            return with_blob(&[]);\n        };\n\n        // SAFETY: the slice cannot outlive the call\n        with_blob(unsafe { blob.as_slice() })\n    }\n\n    /// # Safety\n    /// Caller must ensure lifetime '`b` cannot outlive `self`.\n    unsafe fn blob_borrowed<'a>(&self) -> &'a [u8] {\n        let Some(blob) = self.get_blob() else {\n            return &[];\n        };\n\n        // SAFETY: we need to store that the blob was borrowed\n        // to prevent\n        let blob = self.borrowed_blob.get_or_init(|| blob);\n\n        unsafe { blob.as_slice() }\n    }\n\n    /// # Safety\n    /// Caller must ensure lifetime '`b` cannot outlive `self`.\n    unsafe fn text_borrowed<'b>(&self) -> Result<&'b str, str::Utf8Error> {\n        let Some(blob) = self.get_blob() else {\n            return Ok(\"\");\n        };\n\n        // SAFETY: lifetime of `blob` will be tied to `'b`.\n        let s = str::from_utf8(unsafe { blob.as_slice() })?;\n\n        // We only store the borrow after we ensure the string is valid.\n        self.borrowed_blob.set(blob).ok();\n\n        Ok(s)\n    }\n}\n\nimpl Blob {\n    /// # Safety\n    /// `'a` must not outlive the `sqlite3_value` this blob came from.\n    unsafe fn as_slice<'a>(&self) -> &'a [u8] {\n        slice::from_raw_parts(self.ptr, self.len)\n    }\n}\n"
  },
  {
    "path": "sqlx-test/Cargo.toml",
    "content": "[package]\nname = \"sqlx-test\"\nversion = \"0.1.0\"\nedition.workspace = true\npublish = false\nrust-version.workspace = true\n\n[dependencies]\nsqlx = { default-features = false, path = \"..\" }\nenv_logger = \"0.11\"\ndotenvy = \"0.15.0\"\nanyhow = \"1.0.26\"\n\n[lints]\nworkspace = true\n"
  },
  {
    "path": "sqlx-test/src/lib.rs",
    "content": "use sqlx::pool::PoolOptions;\nuse sqlx::{Connection, Database, Error, Pool};\nuse std::env;\n\npub fn setup_if_needed() {\n    let _ = dotenvy::dotenv();\n    let _ = env_logger::builder().is_test(true).try_init();\n}\n\n// Make a new connection\n// Ensure [dotenvy] and [env_logger] have been setup\npub async fn new<DB>() -> sqlx::Result<DB::Connection>\nwhere\n    DB: Database,\n{\n    setup_if_needed();\n\n    let db_url = env::var(\"DATABASE_URL\").map_err(|e| Error::Configuration(Box::new(e)))?;\n\n    Ok(DB::Connection::connect(&db_url).await?)\n}\n\n// Make a new pool\n// Ensure [dotenvy] and [env_logger] have been setup\npub async fn pool<DB>() -> anyhow::Result<Pool<DB>>\nwhere\n    DB: Database,\n{\n    setup_if_needed();\n\n    let pool = PoolOptions::<DB>::new()\n        .min_connections(0)\n        .max_connections(5)\n        .test_before_acquire(true)\n        .connect(&env::var(\"DATABASE_URL\")?)\n        .await?;\n\n    Ok(pool)\n}\n\n// Test type encoding and decoding\n#[macro_export]\nmacro_rules! test_type {\n    ($name:ident<$ty:ty>($db:ident, $sql:literal, $($text:literal == $value:expr),+ $(,)?)) => {\n        $crate::__test_prepared_type!($name<$ty>($db, $sql, $($text == $value),+));\n        $crate::test_unprepared_type!($name<$ty>($db, $($text == $value),+));\n    };\n\n    ($name:ident<$ty:ty>($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        paste::item! {\n            $crate::__test_prepared_type!($name<$ty>($db, $crate::[< $db _query_for_test_prepared_type >]!(), $($text == $value),+));\n            $crate::test_unprepared_type!($name<$ty>($db, $($text == $value),+));\n        }\n    };\n\n    ($name:ident<$ty:ty>($db:ident, $($text:literal ~= $value:expr),+ $(,)?)) => {\n        paste::item! {\n            $crate::__test_prepared_type!($name<$ty>($db, $crate::[< $db _query_for_test_prepared_geometric_type >]!(), $($text == $value),+));\n        }\n    };\n    ($name:ident<$ty:ty>($db:ident, $($text:literal @= $value:expr),+ $(,)?)) => {\n        paste::item! {\n            $crate::__test_prepared_type!($name<$ty>($db, $crate::[< $db _query_for_test_prepared_geometric_array_type >]!(), $($text == $value),+));\n        }\n    };\n\n\n    ($name:ident($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        $crate::test_type!($name<$name>($db, $($text == $value),+));\n    };\n}\n\n// Test type decoding only\n#[macro_export]\nmacro_rules! test_decode_type {\n    ($name:ident<$ty:ty>($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        $crate::__test_prepared_decode_type!($name<$ty>($db, $($text == $value),+));\n        $crate::test_unprepared_type!($name<$ty>($db, $($text == $value),+));\n    };\n\n    ($name:ident($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        $crate::test_decode_type!($name<$name>($db, $($text == $value),+));\n    };\n}\n\n// Test type encoding and decoding\n#[macro_export]\nmacro_rules! test_prepared_type {\n    ($name:ident<$ty:ty>($db:ident, $sql:literal, $($text:literal == $value:expr),+ $(,)?)) => {\n        $crate::__test_prepared_type!($name<$ty>($db, $sql, $($text == $value),+));\n    };\n\n    ($name:ident<$ty:ty>($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        paste::item! {\n            $crate::__test_prepared_type!($name<$ty>($db, $crate::[< $db _query_for_test_prepared_type >]!(), $($text == $value),+));\n        }\n    };\n\n\n    ($name:ident($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        $crate::__test_prepared_type!($name<$name>($db, $($text == $value),+));\n    };\n}\n\n// Test type decoding for the simple (unprepared) query API\n#[macro_export]\nmacro_rules! test_unprepared_type {\n    ($name:ident<$ty:ty>($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        paste::item! {\n            #[sqlx_macros::test]\n            async fn [< test_unprepared_type_ $name >] () -> anyhow::Result<()> {\n                use sqlx::prelude::*;\n                use sqlx_core::sql_str::AssertSqlSafe;\n                use futures_util::TryStreamExt;\n\n                let mut conn = sqlx_test::new::<$db>().await?;\n\n                $(\n                    let query = format!(\"SELECT {}\", $text);\n                    let mut s = conn.fetch(AssertSqlSafe(query));\n                    let row = s.try_next().await?.unwrap();\n                    let rec = row.try_get::<$ty, _>(0)?;\n\n                    assert_eq!($value, rec);\n\n                    drop(s);\n                )+\n\n                Ok(())\n            }\n        }\n    }\n}\n\n// Test type decoding only for the prepared query API\n#[macro_export]\nmacro_rules! __test_prepared_decode_type {\n    ($name:ident<$ty:ty>($db:ident, $($text:literal == $value:expr),+ $(,)?)) => {\n        paste::item! {\n            #[sqlx_macros::test]\n            async fn [< test_prepared_decode_type_ $name >] () -> anyhow::Result<()> {\n                use sqlx::Row;\n                use sqlx_core::sql_str::AssertSqlSafe;\n\n                let mut conn = sqlx_test::new::<$db>().await?;\n\n                $(\n                    let query = format!(\"SELECT {}\", $text);\n\n                    let row = sqlx::query(AssertSqlSafe(query))\n                        .fetch_one(&mut conn)\n                        .await?;\n\n                    let rec: $ty = row.try_get(0)?;\n\n                    assert_eq!($value, rec);\n                )+\n\n                Ok(())\n            }\n        }\n    };\n}\n\n// Test type encoding and decoding for the prepared query API\n#[macro_export]\nmacro_rules! __test_prepared_type {\n    ($name:ident<$ty:ty>($db:ident, $sql:expr, $($text:literal == $value:expr),+ $(,)?)) => {\n        paste::item! {\n            #[sqlx_macros::test]\n            async fn [< test_prepared_type_ $name >] () -> anyhow::Result<()> {\n                use sqlx::Row;\n                use sqlx_core::sql_str::AssertSqlSafe;\n\n                let mut conn = sqlx_test::new::<$db>().await?;\n\n                $(\n                    let query = format!($sql, $text);\n                    println!(\"{query}\");\n\n                    let row = sqlx::query(AssertSqlSafe(query))\n                        .bind($value)\n                        .bind($value)\n                        .fetch_one(&mut conn)\n                        .await?;\n\n                    let matches: i32 = row.try_get(0)?;\n                    let returned: $ty = row.try_get(1)?;\n                    let round_trip: $ty = row.try_get(2)?;\n\n                    assert!(matches != 0,\n                            \"[1] DB value mismatch; given value: {:?}\\n\\\n                             as returned: {:?}\\n\\\n                             round-trip: {:?}\",\n                            $value, returned, round_trip);\n\n                    assert_eq!($value, returned,\n                            \"[2] DB value mismatch; given value: {:?}\\n\\\n                                     as returned: {:?}\\n\\\n                                     round-trip: {:?}\",\n                                    $value, returned, round_trip);\n\n                    assert_eq!($value, round_trip,\n                            \"[3] DB value mismatch; given value: {:?}\\n\\\n                                     as returned: {:?}\\n\\\n                                     round-trip: {:?}\",\n                                    $value, returned, round_trip);\n                )+\n\n                Ok(())\n            }\n        }\n    };\n}\n\n#[macro_export]\nmacro_rules! MySql_query_for_test_prepared_type {\n    () => {\n        // MySQL 8.0.27 changed `<=>` to return an unsigned integer\n        \"SELECT CAST({0} <=> ? AS SIGNED INTEGER), {0}, ?\"\n    };\n}\n\n#[macro_export]\nmacro_rules! Mssql_query_for_test_prepared_type {\n    () => {\n        \"SELECT CASE WHEN {0} IS NULL AND @p1 IS NULL THEN 1 WHEN {0} = @p1 THEN 1 ELSE 0 END, {0}, @p2\"\n    };\n}\n\n#[macro_export]\nmacro_rules! Sqlite_query_for_test_prepared_type {\n    () => {\n        \"SELECT {0} is ?, {0}, ?\"\n    };\n}\n\n#[macro_export]\nmacro_rules! Postgres_query_for_test_prepared_type {\n    () => {\n        \"SELECT ({0} is not distinct from $1)::int4, {0}, $2\"\n    };\n}\n\n#[macro_export]\nmacro_rules! Postgres_query_for_test_prepared_geometric_type {\n    () => {\n        \"SELECT ({0} ~= $1)::int4, {0}, $2\"\n    };\n}\n\n#[macro_export]\nmacro_rules! Postgres_query_for_test_prepared_geometric_array_type {\n    () => {\n        \"SELECT (SELECT bool_and(geo1.geometry ~= geo2.geometry) FROM unnest({0}) WITH ORDINALITY AS geo1(geometry, idx) JOIN unnest($1) WITH ORDINALITY AS geo2(geometry, idx) ON geo1.idx = geo2.idx)::int4, {0}, $2\"\n    };\n}\n"
  },
  {
    "path": "src/any/install_drivers_note.md",
    "content": "  \nThe underlying database drivers are chosen at runtime from the list set via\n[`install_drivers`][crate::any::install_drivers]. Any use of [`AnyConnection`] or [`AnyPool`]\nwithout this will panic.\n\nIt is recommended to use [`install_default_drivers`][crate::any::install_default_drivers] to activate all currently compiled-in drivers.  \n\n[`AnyConnection`]: sqlx_core::any::AnyConnection\n[`AnyPool`]: sqlx_core::any::AnyPool\n"
  },
  {
    "path": "src/any/mod.rs",
    "content": "//! **SEE DOCUMENTATION BEFORE USE**. Runtime-generic database driver.\n#![doc = include_str!(\"install_drivers_note.md\")]\n\nuse std::sync::Once;\n\npub use sqlx_core::any::driver::install_drivers;\n\npub use sqlx_core::any::{\n    Any, AnyArguments, AnyConnectOptions, AnyExecutor, AnyPoolOptions, AnyQueryResult, AnyRow,\n    AnyStatement, AnyTransactionManager, AnyTypeInfo, AnyTypeInfoKind, AnyValue, AnyValueRef,\n};\n\n#[allow(deprecated)]\npub use sqlx_core::any::AnyKind;\n\npub(crate) mod reexports {\n    /// **SEE DOCUMENTATION BEFORE USE**. Type alias for `Pool<Any>`.\n    #[doc = include_str!(\"install_drivers_note.md\")]\n    pub use sqlx_core::any::AnyPool;\n\n    /// **SEE DOCUMENTATION BEFORE USE**. Runtime-generic database connection.\n    #[doc = include_str!(\"install_drivers_note.md\")]\n    pub use sqlx_core::any::AnyConnection;\n}\n\n/// Install all currently compiled-in drivers for [`AnyConnection`] to use.\n///\n/// May be called multiple times; only the first call will install drivers, subsequent calls\n/// will have no effect.\n///\n/// ### Panics\n/// If [`install_drivers`] has already been called *not* through this function.\n///\n/// [`AnyConnection`]: sqlx_core::any::AnyConnection\npub fn install_default_drivers() {\n    static ONCE: Once = Once::new();\n\n    ONCE.call_once(|| {\n        install_drivers(&[\n            #[cfg(feature = \"mysql\")]\n            sqlx_mysql::any::DRIVER,\n            #[cfg(feature = \"postgres\")]\n            sqlx_postgres::any::DRIVER,\n            #[cfg(feature = \"_sqlite\")]\n            sqlx_sqlite::any::DRIVER,\n        ])\n        .expect(\"non-default drivers already installed\")\n    });\n}\n"
  },
  {
    "path": "src/lib.md",
    "content": "The async SQL toolkit for Rust, built with ❤️ by [the LaunchBadge team].\n\nSee our [README] to get started or [browse our example projects].\nHave a question? [Check our FAQ] or [open a discussion].\n\n### Runtime Support\n\nSQLx supports both the [Tokio] and [async-std] runtimes.\n\nYou choose which runtime SQLx uses by default by enabling one of the following features:\n\n* `runtime-async-std`\n* `runtime-tokio`\n\nIf more than one runtime feature is enabled, the Tokio runtime is used if a Tokio context exists on the current\nthread, i.e. [`tokio::runtime::Handle::try_current()`] returns `Ok`; `async-std` is used otherwise.\n\nNote that while SQLx no longer produces a compile error if zero or multiple runtime features are enabled,\nwhich is useful for libraries building on top of it,\n**the use of nearly any async function in the API will panic without at least one runtime feature enabled**.\n\nThe chief exception is the SQLite driver, which is runtime-agnostic, including its integration with the query macros.\nHowever, [`SqlitePool`] _does_ require runtime support for timeouts and spawning\ninternal management tasks.\n\n### TLS Support\n\nFor securely communicating with SQL servers over an untrusted network connection such as the internet,\nyou can enable Transport Layer Security (TLS) by enabling one of the following features:\n\n* `tls-native-tls`: Enables the [`native-tls`] backend which uses the OS-native TLS capabilities:\n  * SecureTransport on macOS.\n  * SChannel on Windows.\n  * OpenSSL on all other platforms.\n* `tls-rustls`: Enables the [rustls] backend, a cross-platform TLS library.\n  * Only supports TLS revisions 1.2 and 1.3.\n  * If you get `HandshakeFailure` errors when using this feature, it likely means your database server does not support\n    these newer revisions. This might be resolved by enabling or switching to the `tls-native-tls` feature.\n  * rustls supports several providers of cryptographic primitives. The default\n    (enabled when you use the `tls-rustls` feature or `tls-rustls-ring`) is the\n    `ring` provider, which has fewer build-time dependencies but also has fewer\n    features. Alternatively, you can use `tls-rustls-aws-lc-rs` to use the\n    `aws-lc-rs` provider, which enables additional cipher suite support at the cost\n    of more onerous build requirements (depending on platform support).\n\nIf more than one TLS feature is enabled, the `tls-native-tls` feature takes precedent so that it is only necessary to enable\nit to see if it resolves the `HandshakeFailure` error without disabling `tls-rustls`.\n\nConsult the user manual for your database to find the TLS versions it supports.\n\nIf your connection configuration requires a TLS upgrade but TLS support was not enabled, the connection attempt\nwill return an error.\n\n[the LaunchBadge team]: https://www.launchbadge.com\n[README]: https://www.github.com/launchbadge/sqlx/tree/main/README.md\n[browse our example projects]: https://www.github.com/launchbadge/sqlx/tree/main/examples\n[Check our FAQ]: https://www.github.com/launchbadge/sqlx/tree/main/FAQ.md\n[open a discussion]: https://github.com/launchbadge/sqlx/discussions/new?category=q-a\n[Tokio]: https://www.tokio.rs\n[async-std]: https://www.async.rs\n[`tokio::runtime::Handle::try_current()`]: https://docs.rs/tokio/latest/tokio/runtime/struct.Handle.html#method.try_current\n[`native-tls`]: https://docs.rs/native-tls/latest/native_tls/\n[rustls]: https://docs.rs/rustls/latest/rustls/\n"
  },
  {
    "path": "src/lib.rs",
    "content": "#![cfg_attr(docsrs, feature(doc_cfg))]\n#![doc = include_str!(\"lib.md\")]\n\n#[cfg(all(\n    feature = \"sqlite-preupdate-hook\",\n    not(any(feature = \"sqlite\", feature = \"sqlite-unbundled\"))\n))]\ncompile_error!(\n    \"sqlite-preupdate-hook requires either 'sqlite' or 'sqlite-unbundled' to be enabled\"\n);\n\npub use sqlx_core::acquire::Acquire;\npub use sqlx_core::arguments::{Arguments, IntoArguments};\npub use sqlx_core::column::Column;\npub use sqlx_core::column::ColumnIndex;\npub use sqlx_core::column::ColumnOrigin;\npub use sqlx_core::connection::{ConnectOptions, Connection};\npub use sqlx_core::database::{self, Database};\npub use sqlx_core::describe::Describe;\npub use sqlx_core::executor::{Execute, Executor};\npub use sqlx_core::from_row::FromRow;\npub use sqlx_core::pool::{self, Pool};\n#[doc(hidden)]\npub use sqlx_core::query::query_with_result as __query_with_result;\npub use sqlx_core::query::{query, query_with};\npub use sqlx_core::query_as::{query_as, query_as_with};\npub use sqlx_core::query_builder::{self, QueryBuilder};\n#[doc(hidden)]\npub use sqlx_core::query_scalar::query_scalar_with_result as __query_scalar_with_result;\npub use sqlx_core::query_scalar::{query_scalar, query_scalar_with};\npub use sqlx_core::raw_sql::{raw_sql, RawSql};\npub use sqlx_core::row::Row;\npub use sqlx_core::sql_str::{AssertSqlSafe, SqlSafeStr, SqlStr};\npub use sqlx_core::statement::Statement;\npub use sqlx_core::transaction::Transaction;\npub use sqlx_core::type_info::TypeInfo;\npub use sqlx_core::types::Type;\npub use sqlx_core::value::{Value, ValueRef};\npub use sqlx_core::Either;\n\n#[doc(inline)]\npub use sqlx_core::error::{self, Error, Result};\n\n#[cfg(feature = \"migrate\")]\npub use sqlx_core::migrate;\n\n#[cfg(feature = \"mysql\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"mysql\")))]\n#[doc(inline)]\npub use sqlx_mysql::{\n    self as mysql, MySql, MySqlConnection, MySqlExecutor, MySqlPool, MySqlTransaction,\n};\n\n#[cfg(feature = \"postgres\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"postgres\")))]\n#[doc(inline)]\npub use sqlx_postgres::{\n    self as postgres, PgConnection, PgExecutor, PgPool, PgTransaction, Postgres,\n};\n\n#[cfg(feature = \"_sqlite\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"_sqlite\")))]\n#[doc(inline)]\npub use sqlx_sqlite::{\n    self as sqlite, Sqlite, SqliteConnection, SqliteExecutor, SqlitePool, SqliteTransaction,\n};\n\n#[cfg(feature = \"any\")]\n#[cfg_attr(docsrs, doc(cfg(feature = \"any\")))]\npub use crate::any::{reexports::*, Any, AnyExecutor};\n\n#[cfg(any(feature = \"derive\", feature = \"macros\"))]\n#[doc(hidden)]\npub extern crate sqlx_macros;\n\n// derives\n#[cfg(feature = \"derive\")]\n#[doc(hidden)]\npub use sqlx_macros::{FromRow, Type};\n\n// We can't do our normal facade approach with an attribute, but thankfully we can now\n// have docs out-of-line quite easily.\n#[doc = include_str!(\"macros/test.md\")]\n#[cfg(feature = \"macros\")]\npub use sqlx_macros::test;\n\n#[doc(hidden)]\n#[cfg(feature = \"migrate\")]\npub use sqlx_core::testing;\n\n#[doc(hidden)]\npub use sqlx_core::rt::test_block_on;\n\n#[cfg(feature = \"any\")]\npub mod any;\n\n#[cfg(feature = \"macros\")]\nmod macros;\n\n// macro support\n#[cfg(feature = \"macros\")]\n#[doc(hidden)]\npub mod ty_match;\n\n#[cfg(any(feature = \"derive\", feature = \"macros\"))]\n#[doc(hidden)]\npub mod spec_error;\n\n#[doc(hidden)]\npub use sqlx_core::rt as __rt;\n\n/// Conversions between Rust and SQL types.\n///\n/// To see how each SQL type maps to a Rust type, see the corresponding `types` module for each\n/// database:\n///\n///  * Postgres: [postgres::types]\n///  * MySQL: [mysql::types]\n///  * SQLite: [sqlite::types]\n///\n/// Any external types that have had [`Type`] implemented for, are re-exported in this module\n/// for convenience as downstream users need to use a compatible version of the external crate\n/// to take advantage of the implementation.\n///\n/// [`Type`]: types::Type\npub mod types {\n    pub use sqlx_core::types::*;\n\n    #[cfg(feature = \"derive\")]\n    #[doc(hidden)]\n    pub use sqlx_macros::Type;\n}\n\n/// Provides [`Encode`] for encoding values for the database.\npub mod encode {\n    pub use sqlx_core::encode::{Encode, IsNull};\n\n    #[cfg(feature = \"derive\")]\n    #[doc(hidden)]\n    pub use sqlx_macros::Encode;\n}\n\npub use self::encode::Encode;\n\n/// Provides [`Decode`] for decoding values from the database.\npub mod decode {\n    pub use sqlx_core::decode::Decode;\n\n    #[cfg(feature = \"derive\")]\n    #[doc(hidden)]\n    pub use sqlx_macros::Decode;\n}\n\npub use self::decode::Decode;\n\n/// Types and traits for the `query` family of functions and macros.\npub mod query {\n    pub use sqlx_core::query::{Map, Query};\n    pub use sqlx_core::query_as::QueryAs;\n    pub use sqlx_core::query_scalar::QueryScalar;\n}\n\n/// Convenience re-export of common traits.\npub mod prelude {\n    pub use super::Acquire;\n    pub use super::ConnectOptions;\n    pub use super::Connection;\n    pub use super::Decode;\n    pub use super::Encode;\n    pub use super::Executor;\n    pub use super::FromRow;\n    pub use super::IntoArguments;\n    pub use super::Row;\n    pub use super::Statement;\n    pub use super::Type;\n}\n\n#[cfg(feature = \"_unstable-docs\")]\npub use sqlx_core::config as _config;\n\n// NOTE: APIs exported in this module are SemVer-exempt.\n#[doc(hidden)]\npub mod _unstable {\n    pub use sqlx_core::config;\n}\n\n#[doc(hidden)]\n#[cfg_attr(\n    all(feature = \"chrono\", feature = \"time\"),\n    deprecated = \"SQLx has both `chrono` and `time` features enabled, \\\n        which presents an ambiguity when the `query!()` macros are mapping date/time types. \\\n        The `query!()` macros prefer types from `time` by default, \\\n        but this behavior should not be relied upon; \\\n        to resolve the ambiguity, we recommend specifying the preferred crate in a `sqlx.toml` file: \\\n        https://docs.rs/sqlx/latest/sqlx/config/macros/PreferredCrates.html#field.date_time\"\n)]\npub fn warn_on_ambiguous_inferred_date_time_crate() {}\n\n#[doc(hidden)]\n#[cfg_attr(\n    all(feature = \"bigdecimal\", feature = \"rust_decimal\"),\n    deprecated = \"SQLx has both `bigdecimal` and `rust_decimal` features enabled, \\\n        which presents an ambiguity when the `query!()` macros are mapping `NUMERIC`. \\\n        The `query!()` macros prefer `bigdecimal::BigDecimal` by default, \\\n        but this behavior should not be relied upon; \\\n        to resolve the ambiguity, we recommend specifying the preferred crate in a `sqlx.toml` file: \\\n        https://docs.rs/sqlx/latest/sqlx/config/macros/PreferredCrates.html#field.numeric\"\n)]\npub fn warn_on_ambiguous_inferred_numeric_crate() {}\n"
  },
  {
    "path": "src/macros/mod.rs",
    "content": "/// Statically checked SQL query with `println!()` style syntax.\n///\n/// This expands to an instance of [`query::Map`][crate::query::Map] that outputs an ad-hoc anonymous\n/// struct type, if the query has at least one output column that is not `Void`, or `()` (unit) otherwise:\n///\n/// ```rust,ignore\n/// # use sqlx::Connect;\n/// # #[cfg(all(feature = \"mysql\", feature = \"_rt-async-std\"))]\n/// # #[async_std::main]\n/// # async fn main() -> sqlx::Result<()>{\n/// # let db_url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n/// #\n/// # if !(db_url.starts_with(\"mysql\") || db_url.starts_with(\"mariadb\")) { return Ok(()) }\n/// # let mut conn = sqlx::MySqlConnection::connect(db_url).await?;\n/// // let mut conn = <impl sqlx::Executor>;\n/// let account = sqlx::query!(\"select (1) as id, 'Herp Derpinson' as name\")\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// // anonymous struct has `#[derive(Debug)]` for convenience\n/// println!(\"{account:?}\");\n/// println!(\"{}: {}\", account.id, account.name);\n///\n/// # Ok(())\n/// # }\n/// #\n/// # #[cfg(any(not(feature = \"mysql\"), not(feature = \"_rt-async-std\")))]\n/// # fn main() {}\n/// ```\n///\n/// The output columns will be mapped to their corresponding Rust types.\n/// See the documentation for your database for details:\n///\n/// * Postgres: [crate::postgres::types]\n/// * MySQL: [crate::mysql::types]\n///     * Note: due to wire protocol limitations, the query macros do not know when\n///       a column should be decoded as `bool`. It will be inferred to be `i8` instead.\n///       See the link above for details.\n/// * SQLite: [crate::sqlite::types]\n///\n/// **The method you want to call on the result depends on how many rows you're expecting.**\n///\n/// | Number of Rows | Method to Call*             | Returns                                             | Notes |\n/// |----------------| ----------------------------|-----------------------------------------------------|-------|\n/// | None†          | `.execute(...).await`       | `sqlx::Result<DB::QueryResult>`                     | For `INSERT`/`UPDATE`/`DELETE` without `RETURNING`. |\n/// | Zero or One    | `.fetch_optional(...).await`| `sqlx::Result<Option<{adhoc struct}>>`              | Extra rows are ignored. |\n/// | Exactly One    | `.fetch_one(...).await`     | `sqlx::Result<{adhoc struct}>`                      | Errors if no rows were returned. Extra rows are ignored. Aggregate queries, use this. |\n/// | At Least One   | `.fetch(...)`               | `impl Stream<Item = sqlx::Result<{adhoc struct}>>`  | Call `.try_next().await` to get each row result. |\n/// | Multiple   | `.fetch_all(...)`               | `sqlx::Result<Vec<{adhoc struct}>>`  | |\n///\n/// \\* All methods accept one of `&mut {connection type}`, `&mut Transaction` or `&Pool`.  \n/// † Only callable if the query returns no columns; otherwise it's assumed the query *may* return at least one row.\n/// ## Requirements\n/// * The `DATABASE_URL` environment variable must be set at build-time to point to a database\n///   server with the schema that the query string will be checked against.\n///   All variants of `query!()` use [dotenv]<sup>1</sup> so this can be in a `.env` file instead.\n///\n///     * Or, `.sqlx` must exist at the workspace root. See [Offline Mode](#offline-mode-requires-the-offline-feature)\n///       below.\n///\n/// * The query must be a string literal, or concatenation of string literals using `+` (useful\n///   for queries generated by macro), or else it cannot be introspected (and thus cannot be dynamic\n///   or the result of another macro).\n///\n/// * The `QueryAs` instance will be bound to the same database type as `query!()` was compiled\n///   against (e.g. you cannot build against a Postgres database and then run the query against\n///   a MySQL database).\n///\n///     * The schema of the database URL (e.g. `postgres://` or `mysql://`) will be used to\n///       determine the database type.\n///\n/// <sup>1</sup> The `dotenv` crate itself appears abandoned as of [December 2021](https://github.com/dotenv-rs/dotenv/issues/74)\n/// so we now use the [dotenvy] crate instead. The file format is the same.\n///\n/// [dotenv]: https://crates.io/crates/dotenv\n/// [dotenvy]: https://crates.io/crates/dotenvy\n///\n/// ## Configuration with `sqlx.toml`\n/// Multiple crate-wide configuration options are now available, including:\n///\n/// * change the name of the `DATABASE_URL` variable for using multiple databases in the same workspace\n///     * In the initial implementation, a separate crate must be created for each database.\n///       Using multiple databases in the same crate may become possible in the future.\n/// * global type overrides (useful for custom types!)\n/// * per-column type overrides\n/// * force use of a specific crate (e.g. `chrono` when both it and `time` are enabled)\n///\n/// See the [configuration guide] and [reference `sqlx.toml`] for details.\n///\n/// See also `examples/postgres/multi-database` and `examples/postgres/preferred-crates`\n/// for example usage.\n///\n/// [configuration guide]: crate::_config::macros::Config\n/// [reference `sqlx.toml`]: crate::_config::_reference\n///\n/// ## Query Arguments\n/// Like `println!()` and the other formatting macros, you can add bind parameters to your SQL\n/// and this macro will typecheck passed arguments and error on missing ones:\n///\n/// ```rust,ignore\n/// # use sqlx::Connect;\n/// # #[cfg(all(feature = \"mysql\", feature = \"_rt-async-std\"))]\n/// # #[async_std::main]\n/// # async fn main() -> sqlx::Result<()>{\n/// # let db_url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n/// #\n/// # if !(db_url.starts_with(\"mysql\") || db_url.starts_with(\"mariadb\")) { return Ok(()) }\n/// # let mut conn = sqlx::mysql::MySqlConnection::connect(db_url).await?;\n/// // let mut conn = <impl sqlx::Executor>;\n/// let account = sqlx::query!(\n///         // just pretend \"accounts\" is a real table\n///         \"select * from (select (1) as id, 'Herp Derpinson' as name) accounts where id = ?\",\n///         1i32\n///     )\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// println!(\"{account:?}\");\n/// println!(\"{}: {}\", account.id, account.name);\n/// # Ok(())\n/// # }\n/// #\n/// # #[cfg(any(not(feature = \"mysql\"), not(feature = \"_rt-async-std\")))]\n/// # fn main() {}\n/// ```\n///\n/// Bind parameters in the SQL string are specific to the database backend:\n///\n/// * Postgres: `$N` where `N` is the 1-based positional argument index\n/// * MySQL/SQLite: `?` which matches arguments in order that it appears in the query\n///\n/// ## Nullability: Bind Parameters\n/// For a given expected type `T`, both `T` and `Option<T>` are allowed (as well as either\n/// behind references). `Option::None` will be bound as `NULL`, so if binding a type behind `Option`\n/// be sure your query can support it.\n///\n/// Note, however, if binding in a `where` clause, that equality comparisons with `NULL` may not\n/// work as expected; instead you must use `IS NOT NULL` or `IS NULL` to check if a column is not\n/// null or is null, respectively.\n///\n/// In Postgres and MySQL you may also use `IS [NOT] DISTINCT FROM` to compare with a possibly\n/// `NULL` value. In MySQL `IS NOT DISTINCT FROM` can be shortened to `<=>`.\n/// In SQLite you can use `IS` or `IS NOT`. Note that operator precedence may be different.\n///\n/// ## Nullability: Output Columns\n/// In most cases, the database engine can tell us whether or not a column may be `NULL`, and\n/// the `query!()` macro adjusts the field types of the returned struct accordingly.\n///\n/// For Postgres, this only works for columns which come directly from actual tables,\n/// as the implementation will need to query the table metadata to find if a given column\n/// has a `NOT NULL` constraint. Columns that do not have a `NOT NULL` constraint or are the result\n/// of an expression are assumed to be nullable and so `Option<T>` is used instead of `T`.\n///\n/// For MySQL, the implementation looks at [the `NOT_NULL` flag](https://dev.mysql.com/doc/dev/mysql-server/8.0.12/group__group__cs__column__definition__flags.html#ga50377f5ca5b3e92f3931a81fe7b44043)\n/// of [the `ColumnDefinition` structure in `COM_QUERY_OK`](https://dev.mysql.com/doc/internals/en/com-query-response.html#column-definition):\n/// if it is set, `T` is used; if it is not set, `Option<T>` is used.\n///\n/// MySQL appears to be capable of determining the nullability of a result column even if it\n/// is the result of an expression, depending on if the expression may in any case result in\n/// `NULL` which then depends on the semantics of what functions are used. Consult the MySQL\n/// manual for the functions you are using to find the cases in which they return `NULL`.\n///\n/// For SQLite we perform a similar check to Postgres, looking for `NOT NULL` constraints\n/// on columns that come from tables. However, for SQLite we also can step through the output\n/// of `EXPLAIN` to identify columns that may or may not be `NULL`.\n///\n/// To override the nullability of an output column, [see below](#type-overrides-output-columns).\n///\n/// ## Type Overrides: Bind Parameters (Postgres only)\n/// For typechecking of bind parameters, casts using `as` are treated as overrides for the inferred\n/// types of bind parameters and no typechecking is emitted:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent)]\n/// struct MyInt4(i32);\n///\n/// let my_int = MyInt4(1);\n///\n/// sqlx::query!(\"select $1::int4 as id\", my_int as MyInt4)\n/// ```\n///\n/// Using `expr as _` simply signals to the macro to not type-check that bind expression,\n/// and then that syntax is stripped from the expression so as to not trigger type errors.\n///\n/// ## Type Overrides: Output Columns\n/// Type overrides are also available for output columns, utilizing the SQL standard's support\n/// for arbitrary text in column names:\n///\n/// ##### Force Not-Null\n/// Selecting a column `foo as \"foo!\"` (Postgres / SQLite) or `` foo as `foo!` `` (MySQL) overrides\n/// inferred nullability and forces the column to be treated as `NOT NULL`; this is useful e.g. for\n/// selecting expressions in Postgres where we cannot infer nullability:\n///\n/// ```rust,ignore\n/// # async fn main() {\n/// # let mut conn = panic!();\n/// // Postgres: using a raw query string lets us use unescaped double-quotes\n/// // Note that this query wouldn't work in SQLite as we still don't know the exact type of `id`\n/// let record = sqlx::query!(r#\"select 1 as \"id!\"\"#) // MySQL: use \"select 1 as `id!`\" instead\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// // For Postgres this would have been inferred to be Option<i32> instead\n/// assert_eq!(record.id, 1i32);\n/// # }\n///\n/// ```\n///\n/// ##### Force Nullable\n/// Selecting a column `foo as \"foo?\"` (Postgres / SQLite) or `` foo as `foo?` `` (MySQL) overrides\n/// inferred nullability and forces the column to be treated as nullable; this is provided mainly\n/// for symmetry with `!`.\n///\n/// ```rust,ignore\n/// # async fn main() {\n/// # let mut conn = panic!();\n/// // Postgres/SQLite:\n/// let record = sqlx::query!(r#\"select 1 as \"id?\"\"#) // MySQL: use \"select 1 as `id?`\" instead\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// // For Postgres this would have been inferred to be Option<i32> anyway\n/// // but this is just a basic example\n/// assert_eq!(record.id, Some(1i32));\n/// # }\n/// ```\n///\n/// MySQL should be accurate with regards to nullability as it directly tells us when a column is\n/// expected to never be `NULL`. Any mistakes should be considered a bug in MySQL.\n///\n/// However, inference in SQLite and Postgres is more fragile as it depends primarily on observing\n/// `NOT NULL` constraints on columns. If a `NOT NULL` column is brought in by a `LEFT JOIN` then\n/// that column may be `NULL` if its row does not satisfy the join condition. Similarly, a\n/// `FULL JOIN` or `RIGHT JOIN` may generate rows from the primary table that are all `NULL`.\n///\n/// Unfortunately, the result of mistakes in inference is a `UnexpectedNull` error at runtime.\n///\n/// In Postgres, we patch up this inference by analyzing `EXPLAIN VERBOSE` output (which is not\n/// well documented, is highly dependent on the query plan that Postgres generates, and may differ\n/// between releases) to find columns that are the result of left/right/full outer joins. This\n/// analysis errs on the side of producing false positives (marking columns nullable that are not\n/// in practice) but there are likely edge cases that it does not cover yet.\n///\n/// Using `?` as an override we can fix this for columns we know to be nullable in practice:\n///\n/// ```rust,ignore\n/// # async fn main() {\n/// # let mut conn = panic!();\n/// // Ironically this is the exact column we primarily look at to determine nullability in Postgres\n/// let record = sqlx::query!(\n///     r#\"select attnotnull as \"attnotnull?\" from (values (1)) ids left join pg_attribute on false\"#\n/// )\n/// .fetch_one(&mut conn)\n/// .await?;\n///\n/// // Although we do our best, under Postgres this might have been inferred to be `bool`\n/// // In that case, we would have gotten an error\n/// assert_eq!(record.attnotnull, None);\n/// # }\n/// ```\n///\n/// If you find that you need to use this override, please open an issue with a query we can use\n/// to reproduce the problem. For Postgres users, especially helpful would be the output of\n/// `EXPLAIN (VERBOSE, FORMAT JSON) <your query>` with bind parameters substituted in the query\n/// (as the exact value of bind parameters can change the query plan)\n/// and the definitions of any relevant tables (or sufficiently anonymized equivalents).\n///\n/// ##### Force a Different/Custom Type\n/// Selecting a column `foo as \"foo: T\"` (Postgres / SQLite) or `` foo as `foo: T` `` (MySQL)\n/// overrides the inferred type which is useful when selecting user-defined [custom types][crate::Type#compile-time-verification]\n/// (dynamic type checking is still done so if the types are incompatible this will be an error\n/// at runtime instead of compile-time). Note that this syntax alone doesn't override inferred nullability,\n/// but it is compatible with the forced not-null and forced nullable annotations:\n///\n/// ```rust,ignore\n/// # async fn main() {\n/// # let mut conn = panic!();\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent)]\n/// struct MyInt4(i32);\n///\n/// let my_int = MyInt4(1);\n///\n/// // Postgres/SQLite\n/// sqlx::query!(r#\"select 1 as \"id!: MyInt4\"\"#) // MySQL: use \"select 1 as `id: MyInt4`\" instead\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// // For Postgres this would have been inferred to be `Option<i32>`, MySQL/SQLite `i32`\n/// // Note that while using `id: MyInt4` (without the `!`) would work the same for MySQL/SQLite,\n/// // Postgres would expect `Some(MyInt4(1))` and the code wouldn't compile\n/// assert_eq!(record.id, MyInt4(1));\n/// # }\n/// ```\n///\n/// ##### Overrides cheatsheet\n///\n/// | Syntax    | Nullability     | Type       |\n/// | --------- | --------------- | ---------- |\n/// | `foo!`    | Forced not-null | Inferred   |\n/// | `foo?`    | Forced nullable | Inferred   |\n/// | `foo: T`  | Inferred        | Overridden |\n/// | `foo!: T` | Forced not-null | Overridden |\n/// | `foo?: T` | Forced nullable | Overridden |\n///\n/// ## Offline Mode\n/// The macros can be configured to not require a live database connection for compilation,\n/// but it requires a couple extra steps:\n///\n/// * Run `cargo install sqlx-cli`.\n/// * In your project with `DATABASE_URL` set (or in a `.env` file) and the database server running,\n///   run `cargo sqlx prepare`.\n/// * Check the generated `.sqlx` directory into version control.\n/// * Don't have `DATABASE_URL` set during compilation.\n///\n/// Your project can now be built without a database connection (you must omit `DATABASE_URL` or\n/// else it will still try to connect). To update the generated file simply run `cargo sqlx prepare`\n/// again.\n///\n/// To ensure that your `.sqlx` directory is kept up-to-date, both with the queries in your\n/// project and your database schema itself, run\n/// `cargo install sqlx-cli && cargo sqlx prepare --check` in your Continuous Integration script.\n///\n/// See [the README for `sqlx-cli`](https://crates.io/crates/sqlx-cli) for more information.\n///\n/// ## See Also\n/// * [`query_as!`][`crate::query_as!`] if you want to use a struct you can name,\n/// * [`query_file!`][`crate::query_file!`] if you want to define the SQL query out-of-line,\n/// * [`query_file_as!`][`crate::query_file_as!`] if you want both of the above.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query (\n    // in Rust 1.45 we can now invoke proc macros in expression position\n    ($query:expr) => ({\n        $crate::sqlx_macros::expand_query!(source = $query)\n    });\n    // RFC: this semantically should be `$($args:expr),*` (with `$(,)?` to allow trailing comma)\n    // but that doesn't work in 1.45 because `expr` fragments get wrapped in a way that changes\n    // their hygiene, which is fixed in 1.46 so this is technically just a temp. workaround.\n    // My question is: do we care?\n    // I was hoping using the `expr` fragment might aid code completion but it doesn't in my\n    // experience, at least not with IntelliJ-Rust at the time of writing (version 0.3.126.3220-201)\n    // so really the only benefit is making the macros _slightly_ self-documenting, but it's\n    // not like it makes them magically understandable at-a-glance.\n    ($query:expr, $($args:tt)*) => ({\n        $crate::sqlx_macros::expand_query!(source = $query, args = [$($args)*])\n    })\n);\n\n/// A variant of [`query!`][`crate::query!`] which does not check the input or output types. This still does parse\n/// the query to ensure it's syntactically and semantically valid for the current database.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_unchecked (\n    ($query:expr) => ({\n        $crate::sqlx_macros::expand_query!(source = $query, checked = false)\n    });\n    ($query:expr, $($args:tt)*) => ({\n        $crate::sqlx_macros::expand_query!(source = $query, args = [$($args)*], checked = false)\n    })\n);\n\n/// A variant of [`query!`][`crate::query!`] where the SQL query is stored in a separate file.\n///\n/// Useful for large queries and potentially cleaner than multiline strings.\n///\n/// The syntax and requirements (see [`query!`][`crate::query!`]) are the same except the SQL\n/// string is replaced by a file path.\n///\n/// The file must be relative to the project root (the directory containing `Cargo.toml`),\n/// unlike `include_str!()` which uses compiler internals to get the path of the file where it\n/// was invoked.\n///\n/// -----\n///\n/// `examples/queries/account-by-id.sql`:\n/// ```text\n/// select * from (select (1) as id, 'Herp Derpinson' as name) accounts\n/// where id = ?\n/// ```\n///\n/// `src/my_query.rs`:\n/// ```rust,ignore\n/// # use sqlx::Connect;\n/// # #[cfg(all(feature = \"mysql\", feature = \"_rt-async-std\"))]\n/// # #[async_std::main]\n/// # async fn main() -> sqlx::Result<()>{\n/// # let db_url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n/// #\n/// # if !(db_url.starts_with(\"mysql\") || db_url.starts_with(\"mariadb\")) { return Ok(()) }\n/// # let mut conn = sqlx::MySqlConnection::connect(db_url).await?;\n/// let account = sqlx::query_file!(\"tests/test-query-account-by-id.sql\", 1i32)\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// println!(\"{account:?}\");\n/// println!(\"{}: {}\", account.id, account.name);\n///\n/// # Ok(())\n/// # }\n/// #\n/// # #[cfg(any(not(feature = \"mysql\"), not(feature = \"_rt-async-std\")))]\n/// # fn main() {}\n/// ```\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_file (\n    ($path:literal) => ({\n        $crate::sqlx_macros::expand_query!(source_file = $path)\n    });\n    ($path:literal, $($args:tt)*) => ({\n        $crate::sqlx_macros::expand_query!(source_file = $path, args = [$($args)*])\n    })\n);\n\n/// A variant of [`query_file!`][`crate::query_file!`] which does not check the input or output\n/// types. This still does parse the query to ensure it's syntactically and semantically valid\n/// for the current database.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_file_unchecked (\n    ($path:literal) => ({\n        $crate::sqlx_macros::expand_query!(source_file = $path, checked = false)\n    });\n    ($path:literal, $($args:tt)*) => ({\n        $crate::sqlx_macros::expand_query!(source_file = $path, args = [$($args)*], checked = false)\n    })\n);\n\n/// A variant of [`query!`][`crate::query!`] which takes a path to an explicitly defined struct\n/// as the output type.\n///\n/// This lets you return the struct from a function or add your own trait implementations.\n///\n/// **This macro does not use [`FromRow`][crate::FromRow]**; in fact, no trait implementations are\n/// required at all, though this may change in future versions.\n///\n/// The macro maps rows using a struct literal where the names of columns in the query are expected\n/// to be the same as the fields of the struct (but the order does not need to be the same).\n/// The types of the columns are based on the query and not the corresponding fields of the struct,\n/// so this is type-safe as well.\n///\n/// This enforces a few things:\n/// * The query must output at least one column.\n/// * The column names of the query must match the field names of the struct.\n/// * The field types must be the Rust equivalent of their SQL counterparts; see the corresponding\n///   module for your database for mappings:\n///     * Postgres: [crate::postgres::types]\n///     * MySQL: [crate::mysql::types]\n///         * Note: due to wire protocol limitations, the query macros do not know when\n///           a column should be decoded as `bool`. It will be inferred to be `i8` instead.\n///           See the link above for details.\n///     * SQLite: [crate::sqlite::types]\n/// * If a column may be `NULL`, the corresponding field's type must be wrapped in `Option<_>`.\n/// * Neither the query nor the struct may have unused fields.\n///\n/// The only modification to the `query!()` syntax is that the struct name is given before the SQL\n/// string:\n/// ```rust,ignore\n/// # use sqlx::Connect;\n/// # #[cfg(all(feature = \"mysql\", feature = \"_rt-async-std\"))]\n/// # #[async_std::main]\n/// # async fn main() -> sqlx::Result<()>{\n/// # let db_url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n/// #\n/// # if !(db_url.starts_with(\"mysql\") || db_url.starts_with(\"mariadb\")) { return Ok(()) }\n/// # let mut conn = sqlx::MySqlConnection::connect(db_url).await?;\n/// #[derive(Debug)]\n/// struct Account {\n///     id: i32,\n///     name: String\n/// }\n///\n/// // let mut conn = <impl sqlx::Executor>;\n/// let account = sqlx::query_as!(\n///         Account,\n///         \"select * from (select (1) as id, 'Herp Derpinson' as name) accounts where id = ?\",\n///         1i32\n///     )\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// println!(\"{account:?}\");\n/// println!(\"{}: {}\", account.id, account.name);\n///\n/// # Ok(())\n/// # }\n/// #\n/// # #[cfg(any(not(feature = \"mysql\"), not(feature = \"_rt-async-std\")))]\n/// # fn main() {}\n/// ```\n///\n/// **The method you want to call depends on how many rows you're expecting.**\n///\n/// | Number of Rows | Method to Call*             | Returns (`T` being the given struct)   | Notes |\n/// |----------------| ----------------------------|----------------------------------------|-------|\n/// | Zero or One    | `.fetch_optional(...).await`| `sqlx::Result<Option<T>>`              | Extra rows are ignored. |\n/// | Exactly One    | `.fetch_one(...).await`     | `sqlx::Result<T>`                      | Errors if no rows were returned. Extra rows are ignored. Aggregate queries, use this. |\n/// | At Least One   | `.fetch(...)`               | `impl Stream<Item = sqlx::Result<T>>`  | Call `.try_next().await` to get each row result. |\n/// | Multiple       | `.fetch_all(...)`           | `sqlx::Result<Vec<T>>`  | |\n///\n/// \\* All methods accept one of `&mut {connection type}`, `&mut Transaction` or `&Pool`.\n/// (`.execute()` is omitted as this macro requires at least one column to be returned.)\n///\n/// ### Column Type Override: Infer from Struct Field\n/// In addition to the column type overrides supported by [`query!`][`crate::query!`],\n/// [`query_as!()`][`crate::query_as!`] supports an\n/// additional override option:\n///\n/// If you select a column `foo as \"foo: _\"` (Postgres/SQLite) or `` foo as `foo: _` `` (MySQL)\n/// it causes that column to be inferred based on the type of the corresponding field in the given\n/// record struct. Runtime type-checking is still done so an error will be emitted if the types\n/// are not compatible.\n///\n/// This allows you to override the inferred type of a column to instead use a custom-defined type:\n///\n/// ```rust,ignore\n/// #[derive(sqlx::Type)]\n/// #[sqlx(transparent)]\n/// struct MyInt4(i32);\n///\n/// struct Record {\n///     id: MyInt4,\n/// }\n///\n/// let my_int = MyInt4(1);\n///\n/// // Postgres/SQLite\n/// sqlx::query_as!(Record, r#\"select 1 as \"id: _\"\"#) // MySQL: use \"select 1 as `id: _`\" instead\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// assert_eq!(record.id, MyInt4(1));\n/// ```\n///\n/// ### Troubleshooting: \"error: mismatched types\"\n/// If you get a \"mismatched types\" error from an invocation of this macro and the error\n/// isn't pointing specifically at a parameter.\n///\n/// For example, code like this (using a Postgres database):\n///\n/// ```rust,ignore\n/// struct Account {\n///     id: i32,\n///     name: Option<String>,\n/// }\n///\n/// let account = sqlx::query_as!(\n///     Account,\n///     r#\"SELECT id, name from (VALUES (1, 'Herp Derpinson')) accounts(id, name)\"#,\n/// )\n///     .fetch_one(&mut conn)\n///     .await?;\n/// ```\n///\n/// Might produce an error like this:\n/// ```text,ignore\n/// error[E0308]: mismatched types\n///    --> tests/postgres/macros.rs:126:19\n///     |\n/// 126 |       let account = sqlx::query_as!(\n///     |  ___________________^\n/// 127 | |         Account,\n/// 128 | |         r#\"SELECT id, name from (VALUES (1, 'Herp Derpinson')) accounts(id, name)\"#,\n/// 129 | |     )\n///     | |_____^ expected `i32`, found enum `std::option::Option`\n///     |\n///     = note: expected type `i32`\n///                found enum `std::option::Option<i32>`\n/// ```\n///\n/// This means that you need to check that any field of the \"expected\" type (here, `i32`) matches\n/// the Rust type mapping for its corresponding SQL column (see the `types` module of your database,\n/// listed above, for mappings). The \"found\" type is the SQL->Rust mapping that the macro chose.\n///\n/// In the above example, the returned column is inferred to be nullable because it's being\n/// returned from a `VALUES` statement in Postgres, so the macro inferred the field to be nullable\n/// and so used `Option<i32>` instead of `i32`. **In this specific case** we could use\n/// `select id as \"id!\"` to override the inferred nullability because we know in practice\n/// that column will never be `NULL` and it will fix the error.\n///\n/// Nullability inference and type overrides are discussed in detail in the docs for\n/// [`query!`][`crate::query!`].\n///\n/// It unfortunately doesn't appear to be possible right now to make the error specifically mention\n/// the field; this probably requires the `const-panic` feature (still unstable as of Rust 1.45).\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_as (\n    ($out_struct:path, $query:expr) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source = $query)\n    });\n    ($out_struct:path, $query:expr, $($args:tt)*) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source = $query, args = [$($args)*])\n    })\n);\n\n/// Combines the syntaxes of [`query_as!`][`crate::query_as!`] and [`query_file!`][`crate::query_file!`].\n///\n/// Enforces requirements of both macros; see them for details.\n///\n/// ```rust,ignore\n/// # use sqlx::Connect;\n/// # #[cfg(all(feature = \"mysql\", feature = \"_rt-async-std\"))]\n/// # #[async_std::main]\n/// # async fn main() -> sqlx::Result<()>{\n/// # let db_url = dotenvy::var(\"DATABASE_URL\").expect(\"DATABASE_URL must be set\");\n/// #\n/// # if !(db_url.starts_with(\"mysql\") || db_url.starts_with(\"mariadb\")) { return Ok(()) }\n/// # let mut conn = sqlx::MySqlConnection::connect(db_url).await?;\n/// #[derive(Debug)]\n/// struct Account {\n///     id: i32,\n///     name: String\n/// }\n///\n/// // let mut conn = <impl sqlx::Executor>;\n/// let account = sqlx::query_file_as!(Account, \"tests/test-query-account-by-id.sql\", 1i32)\n///     .fetch_one(&mut conn)\n///     .await?;\n///\n/// println!(\"{account:?}\");\n/// println!(\"{}: {}\", account.id, account.name);\n///\n/// # Ok(())\n/// # }\n/// #\n/// # #[cfg(any(not(feature = \"mysql\"), not(feature = \"_rt-async-std\")))]\n/// # fn main() {}\n/// ```\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_file_as (\n    ($out_struct:path, $path:literal) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source_file = $path)\n    });\n    ($out_struct:path, $path:literal, $($args:tt)*) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source_file = $path, args = [$($args)*])\n    })\n);\n\n/// A variant of [`query_as!`][`crate::query_as!`] which does not check the input or output types. This still does parse\n/// the query to ensure it's syntactically and semantically valid for the current database.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_as_unchecked (\n    ($out_struct:path, $query:expr) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source = $query, checked = false)\n    });\n\n    ($out_struct:path, $query:expr, $($args:tt)*) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source = $query, args = [$($args)*], checked = false)\n    })\n);\n\n/// A variant of [`query_file_as!`][`crate::query_file_as!`] which does not check the input or output types. This\n/// still does parse the query to ensure it's syntactically and semantically valid\n/// for the current database.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_file_as_unchecked (\n    ($out_struct:path, $path:literal) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source_file = $path, checked = false)\n    });\n\n    ($out_struct:path, $path:literal, $($args:tt)*) => ( {\n        $crate::sqlx_macros::expand_query!(record = $out_struct, source_file = $path, args = [$($args)*], checked = false)\n    })\n);\n\n/// A variant of [`query!`][`crate::query!`] which expects a single column from the query and evaluates to an\n/// instance of [QueryScalar][crate::query::QueryScalar].\n///\n/// The name of the column is not required to be a valid Rust identifier, however you can still\n/// use the column type override syntax in which case the column name _does_ have to be a valid\n/// Rust identifier for the override to parse properly. If the override parse fails the error\n/// is silently ignored (we just don't have a reliable way to tell the difference). **If you're\n/// getting a different type than expected, please check to see if your override syntax is correct\n/// before opening an issue.**\n///\n/// Wildcard overrides like in [`query_as!`][`crate::query_as!`] are also allowed, in which case the output type\n/// is left up to inference.\n///\n/// See [`query!`][`crate::query!`] for more information.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_scalar (\n    ($query:expr) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source = $query)\n    );\n    ($query:expr, $($args:tt)*) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source = $query, args = [$($args)*])\n    )\n);\n\n/// A variant of [`query_scalar!`][`crate::query_scalar!`] which takes a file path like\n/// [`query_file!`][`crate::query_file!`].\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_file_scalar (\n    ($path:literal) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source_file = $path)\n    );\n    ($path:literal, $($args:tt)*) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source_file = $path, args = [$($args)*])\n    )\n);\n\n/// A variant of [`query_scalar!`][`crate::query_scalar!`] which does not typecheck bind parameters\n/// and leaves the output type to inference.\n/// The query itself is still checked that it is syntactically and semantically\n/// valid for the database, that it only produces one column and that the number of bind parameters\n/// is correct.\n///\n/// For this macro variant the name of the column is irrelevant.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_scalar_unchecked (\n    ($query:expr) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source = $query, checked = false)\n    );\n    ($query:expr, $($args:tt)*) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source = $query, args = [$($args)*], checked = false)\n    )\n);\n\n/// A variant of [`query_file_scalar!`][`crate::query_file_scalar!`] which does not typecheck bind\n/// parameters and leaves the output type to inference.\n/// The query itself is still checked that it is syntactically and\n/// semantically valid for the database, that it only produces one column and that the number of\n/// bind parameters is correct.\n///\n/// For this macro variant the name of the column is irrelevant.\n#[macro_export]\n#[cfg_attr(docsrs, doc(cfg(feature = \"macros\")))]\nmacro_rules! query_file_scalar_unchecked (\n    ($path:literal) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source_file = $path, checked = false)\n    );\n    ($path:literal, $($args:tt)*) => (\n        $crate::sqlx_macros::expand_query!(scalar = _, source_file = $path, args = [$($args)*], checked = false)\n    )\n);\n\n#[allow(clippy::needless_doctest_main)]\n/// Embeds migrations into the binary by expanding to a static instance of [Migrator][crate::migrate::Migrator].\n///\n/// ```rust,ignore\n/// // Consider instead setting\n/// sqlx::migrate!(\"db/migrations\")\n///     .run(&pool)\n///     .await?;\n/// ```\n///\n/// ```rust,ignore\n/// use sqlx::migrate::Migrator;\n///\n/// static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to \"./migrations\"\n/// ```\n///\n/// The directory must be relative to the project root (the directory containing `Cargo.toml`),\n/// unlike `include_str!()` which uses compiler internals to get the path of the file where it\n/// was invoked.\n///\n/// See [MigrationSource][crate::migrate::MigrationSource] for details on structure of the ./migrations directory.\n///\n/// ## Note: Platform-specific Line Endings\n/// Different platforms use different bytes for line endings by default:\n/// * Linux and MacOS use Line Feeds (LF:`\\n`)\n/// * Windows uses Carriage Returns _and_ Line Feeds (CRLF:'\\r\\n')\n///\n/// This may result in un-reproducible hashes across platforms unless taken into account.\n///\n/// One solution is to use a [`.gitattributes` file](https://git-scm.com/docs/gitattributes)\n/// and force `.sql` files to be checked out with Line Feeds:\n///\n/// ```gitattributes\n/// *.sql text eol=lf\n/// ```\n///\n/// Another option is to configure migrations to ignore whitespace.\n/// See the next section for details.\n///\n/// ## Configuration with `sqlx.toml`\n/// Multiple crate-wide configuration options are now available, including:\n///\n/// * creating schemas on database setup\n/// * renaming the `_sqlx_migrations` table or placing it into a new schema\n/// * relocating the migrations directory\n/// * ignoring characters for hashing (such as whitespace and newlines)\n///\n/// See the [configuration guide] and [reference `sqlx.toml`] for details.\n///\n/// `sqlx-cli` can also read these options and use them when setting up or migrating databases.\n///\n/// [configuration guide]: crate::_config::migrate::Config\n/// [reference `sqlx.toml`]: crate::_config::_reference\n///\n/// ## Triggering Recompilation on Migration Changes\n/// In some cases when making changes to embedded migrations, such as adding a new migration without\n/// changing any Rust source files, you might find that `cargo build` doesn't actually do anything,\n/// or when you do `cargo run` your application isn't applying new migrations on startup.\n///\n/// This is because our ability to tell the compiler to watch external files for changes\n/// from a proc-macro is very limited. The compiler by default only re-runs proc macros when\n/// one or more source files have changed, because normally it shouldn't have to otherwise. SQLx is\n/// just weird in that external factors can change the output of proc macros, much to the chagrin of\n/// the compiler team and IDE plugin authors.\n///\n/// As of 0.5.6, we emit `include_str!()` with an absolute path for each migration, but that\n/// only works to get the compiler to watch _existing_ migration files for changes.\n///\n/// Our only options for telling it to watch the whole `migrations/` directory are either via the\n/// user creating a Cargo build script in their project, or using an unstable API on nightly\n/// governed by a `cfg`-flag.\n///\n/// ##### Stable Rust: Cargo Build Script\n/// The only solution on stable Rust right now is to create a Cargo build script in your project\n/// and have it print `cargo:rerun-if-changed=migrations`:\n///\n/// `build.rs`\n/// ```no_run\n/// fn main() {\n///     println!(\"cargo:rerun-if-changed=migrations\");\n/// }\n/// ```\n///\n/// You can run `sqlx migrate build-script` to generate this file automatically.\n///\n/// See: [The Cargo Book: 3.8 Build Scripts; Outputs of the Build Script](https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html#outputs-of-the-build-script)\n///\n/// #### Nightly Rust: `cfg` Flag\n/// The `migrate!()` macro also listens to `--cfg sqlx_macros_unstable`, which will enable\n/// the `track_path` feature to directly tell the compiler to watch the `migrations/` directory:\n///\n/// ```sh,ignore\n/// $ env RUSTFLAGS='--cfg sqlx_macros_unstable' cargo build\n/// ```\n///\n/// Note that this unfortunately will trigger a fully recompile of your dependency tree, at least\n/// for the first time you use it. It also, of course, requires using a nightly compiler.\n///\n/// You can also set it in `build.rustflags` in `.cargo/config.toml`:\n/// ```toml,ignore\n/// [build]\n/// rustflags = [\"--cfg=sqlx_macros_unstable\"]\n/// ```\n///\n/// And then continue building and running your project normally.\n///\n/// If you're building on nightly anyways, it would be extremely helpful to help us test\n/// this feature and find any bugs in it.\n///\n/// Subscribe to [the `track_path` tracking issue](https://github.com/rust-lang/rust/issues/73921)\n/// for discussion and the future stabilization of this feature.\n///\n/// For brevity and because it involves the same commitment to unstable features in `proc_macro`,\n/// if you're using `--cfg procmacro2_semver_exempt` it will also enable this feature\n/// (see [`proc-macro2` docs / Unstable Features](https://docs.rs/proc-macro2/1.0.27/proc_macro2/#unstable-features)).\n#[cfg(feature = \"migrate\")]\n#[macro_export]\nmacro_rules! migrate {\n    ($dir:literal) => {{\n        $crate::sqlx_macros::migrate!($dir)\n    }};\n\n    () => {{\n        $crate::sqlx_macros::migrate!()\n    }};\n}\n"
  },
  {
    "path": "src/macros/test.md",
    "content": "Mark an `async fn` as a test with SQLx support.\n\nThe test will automatically be executed in the async runtime according to the chosen\n`runtime-{async-std, tokio}` feature. If more than one runtime feature is enabled, `runtime-tokio` is preferred.\n\nBy default, this behaves identically to `#[tokio::test]`<sup>1</sup> or `#[async_std::test]`:\n\n```rust\n# // Note if reading these examples directly in `test.md`:\n# // lines prefixed with `#` are not meant to be shown;\n# // they are supporting code to help the examples to compile successfully.\n# #[cfg(feature = \"_rt-tokio\")]\n#[sqlx::test]\nasync fn test_async_fn() {\n    tokio::task::yield_now().await;\n} \n```\n\nHowever, several advanced features are also supported as shown in the next section.\n\n<sup>1</sup>`#[sqlx::test]` does not recognize any of the control arguments supported by `#[tokio::test]`\nas that would have complicated the implementation. If your use case requires any of those, feel free to open an issue.\n\n### Automatic Test Database Management (requires `migrate` feature)\n\n`#[sqlx::test]` can automatically create test databases for you and provide live connections to your test.\n\nFor every annotated function, a new test database is created so tests can run against a live database\nbut are isolated from each other.\n\nThis feature is activated by changing the signature of your test function. The following signatures are supported:\n\n* `async fn(Pool<DB>) -> Ret`\n    * the `Pool`s used by all running tests share a single connection limit to avoid exceeding the server's limit.\n* `async fn(PoolConnection<DB>) -> Ret`\n    * `PoolConnection<Postgres>`, etc.\n* `async fn(PoolOptions<DB>, impl ConnectOptions<DB>) -> Ret`\n    * Where `impl ConnectOptions` is, e.g, `PgConnectOptions`, `MySqlConnectOptions`, etc.\n    * If your test wants to create its own `Pool` (for example, to set pool callbacks or to modify `ConnectOptions`),\n      you can use this signature.\n\nWhere `DB` is a supported `Database` type and `Ret` is `()` or `Result<_, _>`.\n\n##### Supported Databases\n\nMost of these will require you to set `DATABASE_URL` as an environment variable\nor in a `.env` file like `sqlx::query!()` _et al_, to give the test driver a superuser connection with which\nto manage test databases.\n\n| Database | Requires `DATABASE_URL` |\n|----------|-------------------------| \n| Postgres | Yes                     |\n| MySQL    | Yes                     |\n| SQLite   | No<sup>2</sup>          |\n\nTest databases are automatically cleaned up as tests succeed, but failed tests will leave their databases in-place\nto facilitate debugging. Note that to simplify the implementation, panics are _always_ considered to be failures,\neven for `#[should_panic]` tests.\n\nTo limit disk space usage, any previously created test databases will be deleted the next time a test binary using\n`#[sqlx::test]` is run.\n\n```rust,no_run\n# #[cfg(all(feature = \"migrate\", feature = \"postgres\"))]\n# mod example { \nuse sqlx::{PgPool, Row};\n\n#[sqlx::test]\nasync fn basic_test(pool: PgPool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n\n    let foo = sqlx::query(\"SELECT * FROM foo\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo.get::<String, _>(\"bar\"), \"foobar!\");\n    \n    Ok(())\n}\n# }     \n```\n\n<sup>2</sup> SQLite defaults to `target/sqlx/test-dbs/<path>.sqlite` where `<path>` is the path of the test function\nconverted to a filesystem path (`::` replaced with `/`).\n\n### Automatic Migrations (requires `migrate` feature)\n\nTo ensure a straightforward test implementation against a fresh test database, migrations are automatically applied if a\n`migrations` folder is found in the same directory as `CARGO_MANIFEST_DIR` (the directory where the current crate's\n`Cargo.toml` resides).\n\nYou can override the resolved path relative to `CARGO_MANIFEST_DIR` in the attribute (global overrides are not currently\nsupported):\n\n```rust,ignore\n# #[cfg(all(feature = \"migrate\", feature = \"postgres\"))]\n# mod example { \nuse sqlx::{PgPool, Row};\n\n#[sqlx::test(migrations = \"foo_migrations\")]\nasync fn basic_test(pool: PgPool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n\n    let foo = sqlx::query(\"SELECT * FROM foo\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo.get::<String, _>(\"bar\"), \"foobar!\");\n    \n    Ok(())\n}\n# }\n```\n\nOr if you're already embedding migrations in your main crate, you can reference them directly:\n\n`foo_crate/lib.rs`\n\n```rust,ignore\npub static MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!(\"foo_migrations\");\n```\n\n`foo_crate/tests/foo_test.rs`\n\n```rust,no_run\n# #[cfg(all(feature = \"migrate\", feature = \"postgres\"))]\n# mod example { \nuse sqlx::{PgPool, Row};\n\n# // This is standing in for the main crate since doc examples don't support multiple crates.\n# mod foo_crate { \n#   use std::borrow::Cow;\n#   static MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate::Migrator::DEFAULT;\n# } \n\n// You could also do `use foo_crate::MIGRATOR` and just refer to it as `MIGRATOR` here.\n#[sqlx::test(migrator = \"foo_crate::MIGRATOR\")]\nasync fn basic_test(pool: PgPool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n\n    let foo = sqlx::query(\"SELECT * FROM foo\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo.get::<String, _>(\"bar\"), \"foobar!\");\n    \n    Ok(())\n}\n# }\n```\n\nOr disable migrations processing entirely:\n\n```rust,no_run\n# #[cfg(all(feature = \"migrate\", feature = \"postgres\"))]\n# mod example { \nuse sqlx::{PgPool, Row};\n\n#[sqlx::test(migrations = false)]\nasync fn basic_test(pool: PgPool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n    \n    conn.execute(\"CREATE TABLE foo(bar text)\").await?;\n\n    let foo = sqlx::query(\"SELECT * FROM foo\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo.get::<String, _>(\"bar\"), \"foobar!\");\n    \n    Ok(())\n}\n# }\n```\n\n### Automatic Fixture Application (requires `migrate` feature)\n\nSince tests are isolated from each other but may require data to already exist in the database to keep from growing\nexponentially in complexity, `#[sqlx::test]` also supports applying test fixtures, which are SQL scripts that function\nsimilarly to migrations but are solely intended to insert test data and be arbitrarily composable.\n\nImagine a basic social app that has users, posts and comments. To test the comment routes, you'd want\nthe database to already have users and posts in it so the comments tests don't have to duplicate that work.\n\nYou can either pass a list of fixture to the attribute `fixtures` in three different operating modes:\n\n1) Pass a list of references files in `./fixtures` (resolved as `./fixtures/{name}.sql`, `.sql` added only if extension\n   is missing);\n2) Pass a list of file paths (including associated extension), in which case they can either be absolute, or relative to\n   the current file;\n3) Pass a `path = <path to folder>` parameter and a `scripts(<filename_1>, <filename_2>, ...)` parameter that are\n   relative to the provided path (resolved as `{path}/{filename_x}.sql`, `.sql` added only if extension is missing).\n\nIn any case they will be applied in the given order<sup>3</sup>:\n\n```rust,no_run\n# #[cfg(all(feature = \"migrate\", feature = \"postgres\"))]\n# mod example { \n# struct App {}\n# fn create_app(pool: PgPool) -> App { App {} }\nuse sqlx::PgPool;\nuse serde_json::json;\n\n// Alternatives:\n// #[sqlx::test(fixtures(\"./fixtures/users.sql\", \"./fixtures/posts.sql\"))]\n// or\n// #[sqlx::test(fixtures(path = \"./fixtures\", scripts(\"users\", \"posts\")))]\n#[sqlx::test(fixtures(\"users\", \"posts\"))]\nasync fn test_create_comment(pool: PgPool) -> sqlx::Result<()> {\n    // See examples/postgres/social-axum-with-tests for a more in-depth example. \n    let mut app = create_app(pool);     \n    \n    let comment = test_request(\n        &mut app, \"POST\", \"/v1/comment\", json! { \"postId\": \"1234\" }\n    ).await?;\n    \n    assert_eq!(comment[\"postId\"], \"1234\");\n    \n    Ok(())\n}\n# }\n```\n\nMultiple `fixtures` attributes can be used to combine different operating modes.\n\n<sup>3</sup>Ordering for test fixtures is entirely up to the application, and each test may choose which fixtures to\napply and which to omit. However, since each fixture is applied separately (sent as a single command string, so wrapped\nin an implicit `BEGIN` and `COMMIT`), you will want to make sure to order the fixtures such that foreign key\nrequirements are always satisfied, or else you might get errors. \n"
  },
  {
    "path": "src/spec_error.rs",
    "content": "use std::any::Any;\nuse std::error::Error;\nuse std::fmt::{Debug, Display};\n\n// Autoderef specialization similar to `clap::value_parser!()`.\npub struct SpecErrorWrapper<E>(pub E);\n\npub trait SpecError<E>: Sized {\n    fn __sqlx_spec_error(\n        &self,\n    ) -> fn(SpecErrorWrapper<E>) -> Box<dyn Error + Send + Sync + 'static>;\n}\n\nimpl<E> SpecError<E> for &&&&SpecErrorWrapper<E>\nwhere\n    E: Error + Send + Sync + 'static,\n{\n    fn __sqlx_spec_error(\n        &self,\n    ) -> fn(SpecErrorWrapper<E>) -> Box<dyn Error + Send + Sync + 'static> {\n        |e| Box::new(e.0)\n    }\n}\n\nimpl<E> SpecError<E> for &&&SpecErrorWrapper<E>\nwhere\n    E: Display,\n{\n    fn __sqlx_spec_error(\n        &self,\n    ) -> fn(SpecErrorWrapper<E>) -> Box<dyn Error + Send + Sync + 'static> {\n        |e| e.0.to_string().into()\n    }\n}\n\nimpl<E> SpecError<E> for &&SpecErrorWrapper<E>\nwhere\n    E: Debug,\n{\n    fn __sqlx_spec_error(\n        &self,\n    ) -> fn(SpecErrorWrapper<E>) -> Box<dyn Error + Send + Sync + 'static> {\n        |e| format!(\"{:?}\", e.0).into()\n    }\n}\n\nimpl<E> SpecError<E> for &SpecErrorWrapper<E>\nwhere\n    E: Any,\n{\n    fn __sqlx_spec_error(\n        &self,\n    ) -> fn(SpecErrorWrapper<E>) -> Box<dyn Error + Send + Sync + 'static> {\n        |_e| format!(\"unprintable error: {}\", std::any::type_name::<E>()).into()\n    }\n}\n\nimpl<E> SpecError<E> for SpecErrorWrapper<E> {\n    fn __sqlx_spec_error(\n        &self,\n    ) -> fn(SpecErrorWrapper<E>) -> Box<dyn Error + Send + Sync + 'static> {\n        |_e| \"unprintable error: (unprintable type)\".into()\n    }\n}\n\n#[doc(hidden)]\n#[macro_export]\nmacro_rules! __spec_error {\n    ($e:expr) => {{\n        use $crate::spec_error::{SpecError, SpecErrorWrapper};\n\n        let wrapper = SpecErrorWrapper($e);\n        let wrap_err = wrapper.__sqlx_spec_error();\n        wrap_err(wrapper)\n    }};\n}\n\n#[test]\nfn test_spec_error() {\n    #[derive(Debug)]\n    struct DebugError;\n\n    struct AnyError;\n\n    let _e: Box<dyn Error + Send + Sync + 'static> =\n        __spec_error!(std::io::Error::from(std::io::ErrorKind::Unsupported));\n\n    let _e: Box<dyn Error + Send + Sync + 'static> = __spec_error!(\"displayable error\");\n\n    let _e: Box<dyn Error + Send + Sync + 'static> = __spec_error!(DebugError);\n\n    let _e: Box<dyn Error + Send + Sync + 'static> = __spec_error!(AnyError);\n\n    let _e: Box<dyn Error + Send + Sync + 'static> = __spec_error!(&1i32);\n}\n"
  },
  {
    "path": "src/ty_match.rs",
    "content": "use std::marker::PhantomData;\n\n// These types allow the `query!()` and friends to compare a given parameter's type to\n// an expected parameter type even if the former is behind a reference or in `Option`.\n\n// For query parameters, Postgres gives us a single type ID which we convert to an \"expected\" or\n// preferred Rust type, but there can actually be several types that are compatible for a given type\n// in input position. E.g. for an expected parameter of `String`, we want to accept `String`,\n// `Option<String>`, `&str` and `Option<&str>`. And for the best compiler errors we don't just\n// want an `IsCompatible` trait (at least not without `#[on_unimplemented]` which is unstable\n// for the foreseeable future).\n\n// We can do this by using autoref (for method calls, the compiler adds reference ops until\n// it finds a matching impl) with impls that technically don't overlap as a hacky form of\n// specialization (but this works only if all types are statically known, i.e. we're not in a\n// generic context; this should suit 99% of use cases for the macros).\n\n#[allow(clippy::just_underscores_and_digits)]\npub fn same_type<T>(_1: &T, _2: &T) {}\n\npub struct WrapSame<T, U>(PhantomData<T>, PhantomData<U>);\n\nimpl<T, U> WrapSame<T, U> {\n    pub fn new(_arg: &U) -> Self {\n        WrapSame(PhantomData, PhantomData)\n    }\n}\n\npub trait WrapSameExt: Sized {\n    type Wrapped;\n\n    fn wrap_same(self) -> Self::Wrapped {\n        panic!(\"only for type resolution\")\n    }\n}\n\nimpl<T, U> WrapSameExt for WrapSame<T, Option<U>> {\n    type Wrapped = Option<T>;\n}\n\nimpl<T, U> WrapSameExt for &'_ WrapSame<T, U> {\n    type Wrapped = T;\n}\n\npub struct MatchBorrow<T, U>(PhantomData<T>, PhantomData<U>);\n\nimpl<T, U> MatchBorrow<T, U> {\n    pub fn new(t: T, _u: &U) -> (T, Self) {\n        (t, MatchBorrow(PhantomData, PhantomData))\n    }\n}\n\npub trait MatchBorrowExt: Sized {\n    type Matched;\n\n    fn match_borrow(self) -> Self::Matched {\n        panic!(\"only for type resolution\")\n    }\n}\n\nimpl<'a> MatchBorrowExt for MatchBorrow<Option<&'a str>, Option<String>> {\n    type Matched = Option<&'a str>;\n}\n\nimpl<'a> MatchBorrowExt for MatchBorrow<Option<&'a [u8]>, Option<Vec<u8>>> {\n    type Matched = Option<&'a [u8]>;\n}\n\nimpl<'a> MatchBorrowExt for MatchBorrow<Option<&'a str>, Option<&'a String>> {\n    type Matched = Option<&'a str>;\n}\n\nimpl<'a> MatchBorrowExt for MatchBorrow<Option<&'a [u8]>, Option<&'a Vec<u8>>> {\n    type Matched = Option<&'a [u8]>;\n}\n\nimpl<'a> MatchBorrowExt for MatchBorrow<&'a str, String> {\n    type Matched = &'a str;\n}\n\nimpl<'a> MatchBorrowExt for MatchBorrow<&'a [u8], Vec<u8>> {\n    type Matched = &'a [u8];\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<&'_ T, T> {\n    type Matched = T;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<&'_ &'_ T, T> {\n    type Matched = T;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<T, &'_ T> {\n    type Matched = T;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<T, &'_ &'_ T> {\n    type Matched = T;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<Option<&'_ T>, Option<T>> {\n    type Matched = Option<T>;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<Option<&'_ &'_ T>, Option<T>> {\n    type Matched = Option<T>;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<Option<T>, Option<&'_ T>> {\n    type Matched = Option<T>;\n}\n\nimpl<T> MatchBorrowExt for MatchBorrow<Option<T>, Option<&'_ &'_ T>> {\n    type Matched = Option<T>;\n}\n\nimpl<T, U> MatchBorrowExt for &'_ MatchBorrow<T, U> {\n    type Matched = U;\n}\n\npub fn conjure_value<T>() -> T {\n    panic!()\n}\n\npub fn dupe_value<T>(_t: &T) -> T {\n    panic!()\n}\n\n#[test]\nfn test_dupe_value() {\n    let val = &(String::new(),);\n\n    if false {\n        let _: i32 = dupe_value(&0i32);\n        let _: String = dupe_value(&String::new());\n        let _: String = dupe_value(&val.0);\n    }\n}\n\n#[test]\nfn test_wrap_same() {\n    if false {\n        let _: i32 = WrapSame::<i32, _>::new(&0i32).wrap_same();\n        let _: i32 = WrapSame::<i32, _>::new(&\"hello, world!\").wrap_same();\n        let _: Option<i32> = WrapSame::<i32, _>::new(&Some(String::new())).wrap_same();\n    }\n}\n\n#[test]\nfn test_match_borrow() {\n    if false {\n        let (_, match_borrow) = MatchBorrow::new(\"\", &String::new());\n        let _: &str = match_borrow.match_borrow();\n\n        let (_, match_borrow) = MatchBorrow::new(&&0i64, &0i64);\n        let _: i64 = match_borrow.match_borrow();\n\n        let (_, match_borrow) = MatchBorrow::new(&0i64, &0i64);\n        let _: i64 = match_borrow.match_borrow();\n\n        let (_, match_borrow) = MatchBorrow::new(0i64, &0i64);\n        let _: i64 = match_borrow.match_borrow();\n    }\n}\n"
  },
  {
    "path": "tests/.dockerignore",
    "content": "*\n!certs/*\n!certs/keys/*\n!mysql/my.cnf\n!mssql/*.sh\n!postgres/pg_hba.conf\n!*/*.sql\n"
  },
  {
    "path": "tests/.env",
    "content": "# environment values for docker-compose\nCOMPOSE_PROJECT_NAME=sqlx\n"
  },
  {
    "path": "tests/.gitignore",
    "content": "!.env\n__pycache__\n"
  },
  {
    "path": "tests/README.md",
    "content": "\n\n### Running Tests\nSQLx uses docker to run many compatible database systems for integration testing. You'll need to [install docker](https://docs.docker.com/engine/) to run the full suite. You can validate your docker installation with:\n    \n    $ docker run hello-world\n\nStart the databases with `docker-compose` before running tests: \n\n    $ docker-compose up\n\nRun all tests against all supported databases using:\n\n    $ ./x.py\n\nIf you see test failures, or want to run a more specific set of tests against a specific database, you can specify both the features to be tests and the DATABASE_URL. e.g.\n\n    $ DATABASE_URL=mysql://root:password@127.0.0.1:49183/sqlx cargo test --no-default-features --features macros,offline,any,all-types,mysql,runtime-async-std-native-tls\n"
  },
  {
    "path": "tests/any/any.rs",
    "content": "use sqlx::any::{install_default_drivers, AnyRow};\nuse sqlx::{Any, Connection, Executor, Row};\nuse sqlx_core::error::BoxDynError;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse sqlx_core::Error;\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_connects() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let mut conn = new::<Any>().await?;\n\n    let value = sqlx::query(\"select 1 + 5\")\n        .try_map(|row: AnyRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(6i32, value);\n\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_pings() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let mut conn = new::<Any>().await?;\n\n    conn.ping().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes_with_pool() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let pool = sqlx_test::pool::<Any>().await?;\n\n    let rows = pool.fetch_all(\"SELECT 1; SElECT 2\").await?;\n\n    assert_eq!(rows.len(), 2);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_does_not_stop_stream_after_decoding_error() -> anyhow::Result<()> {\n    use futures_util::stream::StreamExt;\n\n    sqlx::any::install_default_drivers();\n\n    // see https://github.com/launchbadge/sqlx/issues/1884\n    let pool = sqlx_test::pool::<Any>().await?;\n\n    #[derive(Debug, PartialEq)]\n    struct MyType;\n    impl<'a> sqlx::FromRow<'a, AnyRow> for MyType {\n        fn from_row(row: &'a AnyRow) -> sqlx::Result<Self> {\n            let n = row.try_get::<i32, _>(0)?;\n            if n == 1 {\n                Err(sqlx::Error::RowNotFound)\n            } else {\n                Ok(MyType)\n            }\n        }\n    }\n\n    let rows = sqlx::query_as(\"SELECT 0 UNION ALL SELECT 1 UNION ALL SELECT 2\")\n        .fetch(&pool)\n        .map(|r| r.ok())\n        .collect::<Vec<_>>()\n        .await;\n\n    assert_eq!(rows, vec![Some(MyType), None, Some(MyType)]);\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_gets_by_name() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let mut conn = new::<Any>().await?;\n\n    let row = conn.fetch_one(\"SELECT 1 as _1\").await?;\n    let val: i32 = row.get(\"_1\");\n\n    assert_eq!(val, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fail_and_recover() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let mut conn = new::<Any>().await?;\n\n    for i in 0..10 {\n        // make a query that will fail\n        let res = conn\n            .execute(\"INSERT INTO not_found (column) VALUES (10)\")\n            .await;\n\n        assert!(res.is_err());\n\n        // now try and use the connection\n        let val: i32 = conn\n            .fetch_one(AssertSqlSafe(format!(\"SELECT {i}\")))\n            .await?\n            .get_unchecked(0);\n\n        assert_eq!(val, i);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fail_and_recover_with_pool() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let pool = sqlx_test::pool::<Any>().await?;\n\n    for i in 0..10 {\n        // make a query that will fail\n        let res = pool\n            .execute(\"INSERT INTO not_found (column) VALUES (10)\")\n            .await;\n\n        assert!(res.is_err());\n\n        // now try and use the connection\n        let val: i32 = pool\n            .fetch_one(AssertSqlSafe(format!(\"SELECT {i}\")))\n            .await?\n            .get_unchecked(0);\n\n        assert_eq!(val, i);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_query_by_string_args() -> sqlx::Result<()> {\n    install_default_drivers();\n\n    let mut conn = new::<Any>().await?;\n\n    let string = \"Hello, world!\".to_string();\n    let ref tuple = (\"Hello, world!\".to_string(),);\n\n    #[cfg(feature = \"postgres\")]\n    const SQL: &str =\n        \"SELECT 'Hello, world!' as string where 'Hello, world!' in ($1, $2, $3, $4, $5, $6, $7)\";\n\n    #[cfg(not(feature = \"postgres\"))]\n    const SQL: &str =\n        \"SELECT 'Hello, world!' as string where 'Hello, world!' in (?, ?, ?, ?, ?, ?, ?)\";\n\n    {\n        let query = sqlx::query(SQL)\n            // validate flexibility of lifetimes\n            .bind(&string)\n            .bind(&string[..])\n            .bind(Some(&string))\n            .bind(Some(&string[..]))\n            .bind(&Option::<String>::None)\n            .bind(&string.clone())\n            .bind(&tuple.0); // should not get \"temporary value is freed at the end of this statement\" here\n\n        let result = query.fetch_one(&mut conn).await?;\n\n        let column_0: String = result.try_get(0)?;\n\n        assert_eq!(column_0, string);\n    }\n\n    {\n        let mut query = sqlx::query(SQL);\n\n        let query = || -> Result<_, BoxDynError> {\n            // validate flexibility of lifetimes\n            query.try_bind(&string)?;\n            query.try_bind(&string[..])?;\n            query.try_bind(Some(&string))?;\n            query.try_bind(Some(&string[..]))?;\n            query.try_bind(&Option::<String>::None)?;\n            query.try_bind(&string.clone())?;\n            query.try_bind(&tuple.0)?;\n\n            Ok(query)\n        }()\n        .map_err(Error::Encode)?;\n\n        let result = query.fetch_one(&mut conn).await?;\n\n        let column_0: String = result.try_get(0)?;\n\n        assert_eq!(column_0, string);\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/any/pool.rs",
    "content": "use sqlx::any::{AnyConnectOptions, AnyPoolOptions};\nuse sqlx::Executor;\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse std::sync::{\n    atomic::{AtomicI32, AtomicUsize, Ordering},\n    Arc, Mutex,\n};\nuse std::time::Duration;\n\n#[sqlx_macros::test]\nasync fn pool_should_invoke_after_connect() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let counter = Arc::new(AtomicUsize::new(0));\n\n    let pool = AnyPoolOptions::new()\n        .after_connect({\n            let counter = counter.clone();\n            move |_conn, _meta| {\n                let counter = counter.clone();\n                Box::pin(async move {\n                    counter.fetch_add(1, Ordering::SeqCst);\n\n                    Ok(())\n                })\n            }\n        })\n        .connect(&dotenvy::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let _ = pool.acquire().await?;\n    let _ = pool.acquire().await?;\n    let _ = pool.acquire().await?;\n    let _ = pool.acquire().await?;\n\n    // since connections are released asynchronously,\n    // `.after_connect()` may be called more than once\n    assert!(counter.load(Ordering::SeqCst) >= 1);\n\n    Ok(())\n}\n\n// https://github.com/launchbadge/sqlx/issues/527\n#[sqlx_macros::test]\nasync fn pool_should_be_returned_failed_transactions() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let pool = AnyPoolOptions::new()\n        .max_connections(2)\n        .acquire_timeout(Duration::from_secs(3))\n        .connect(&dotenvy::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let query = \"blah blah\";\n\n    let mut tx = pool.begin().await?;\n    let res = sqlx::query(query).execute(&mut *tx).await;\n    assert!(res.is_err());\n    drop(tx);\n\n    let mut tx = pool.begin().await?;\n    let res = sqlx::query(query).execute(&mut *tx).await;\n    assert!(res.is_err());\n    drop(tx);\n\n    let mut tx = pool.begin().await?;\n    let res = sqlx::query(query).execute(&mut *tx).await;\n    assert!(res.is_err());\n    drop(tx);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_pool_callbacks() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n    struct ConnStats {\n        id: i32,\n        before_acquire_calls: i32,\n        after_release_calls: i32,\n    }\n\n    sqlx_test::setup_if_needed();\n\n    let conn_options: AnyConnectOptions = std::env::var(\"DATABASE_URL\")?.parse()?;\n\n    let current_id = AtomicI32::new(0);\n\n    let pool = AnyPoolOptions::new()\n        .max_connections(1)\n        .acquire_timeout(Duration::from_secs(5))\n        .after_connect(move |conn, meta| {\n            assert_eq!(meta.age, Duration::ZERO);\n            assert_eq!(meta.idle_for, Duration::ZERO);\n\n            let id = current_id.fetch_add(1, Ordering::AcqRel);\n\n            Box::pin(async move {\n                let statement = format!(\n                    // language=SQL\n                    r#\"\n                    CREATE TEMPORARY TABLE conn_stats(\n                        id int primary key,\n                        before_acquire_calls int default 0,\n                        after_release_calls int default 0\n                    );\n                    INSERT INTO conn_stats(id) VALUES ({});\n                    \"#,\n                    // Until we have generalized bind parameters\n                    id\n                );\n\n                conn.execute(AssertSqlSafe(statement)).await?;\n                Ok(())\n            })\n        })\n        .before_acquire(|conn, meta| {\n            // `age` and `idle_for` should both be nonzero\n            assert_ne!(meta.age, Duration::ZERO);\n            assert_ne!(meta.idle_for, Duration::ZERO);\n\n            Box::pin(async move {\n                // MySQL and MariaDB don't support UPDATE ... RETURNING\n                sqlx::query(\n                    r#\"\n                        UPDATE conn_stats\n                        SET before_acquire_calls = before_acquire_calls + 1\n                    \"#,\n                )\n                .execute(&mut *conn)\n                .await?;\n\n                let stats: ConnStats = sqlx::query_as(\"SELECT * FROM conn_stats\")\n                    .fetch_one(conn)\n                    .await?;\n\n                // For even IDs, cap by the number of before_acquire calls.\n                // Ignore the check for odd IDs.\n                Ok((stats.id & 1) == 1 || stats.before_acquire_calls < 3)\n            })\n        })\n        .after_release(|conn, meta| {\n            // `age` should be nonzero but `idle_for` should be zero.\n            assert_ne!(meta.age, Duration::ZERO);\n            assert_eq!(meta.idle_for, Duration::ZERO);\n\n            Box::pin(async move {\n                sqlx::query(\n                    r#\"\n                        UPDATE conn_stats\n                        SET after_release_calls = after_release_calls + 1\n                    \"#,\n                )\n                .execute(&mut *conn)\n                .await?;\n\n                let stats: ConnStats = sqlx::query_as(\"SELECT * FROM conn_stats\")\n                    .fetch_one(conn)\n                    .await?;\n\n                // For odd IDs, cap by the number of before_release calls.\n                // Ignore the check for even IDs.\n                Ok((stats.id & 1) == 0 || stats.after_release_calls < 4)\n            })\n        })\n        // Don't establish a connection yet.\n        .connect_lazy_with(conn_options);\n\n    // Expected pattern of (id, before_acquire_calls, after_release_calls)\n    let pattern = [\n        // The connection pool starts empty.\n        (0, 0, 0),\n        (0, 1, 1),\n        (0, 2, 2),\n        (1, 0, 0),\n        (1, 1, 1),\n        (1, 2, 2),\n        // We should expect one more `acquire` because the ID is odd\n        (1, 3, 3),\n        (2, 0, 0),\n        (2, 1, 1),\n        (2, 2, 2),\n        (3, 0, 0),\n    ];\n\n    for (id, before_acquire_calls, after_release_calls) in pattern {\n        let conn_stats: ConnStats = sqlx::query_as(\"SELECT * FROM conn_stats\")\n            .fetch_one(&pool)\n            .await?;\n\n        assert_eq!(\n            conn_stats,\n            ConnStats {\n                id,\n                before_acquire_calls,\n                after_release_calls\n            }\n        );\n    }\n\n    pool.close().await;\n\n    Ok(())\n}\n\n#[ignore]\n#[sqlx_macros::test]\nasync fn test_connection_maintenance() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n    sqlx_test::setup_if_needed();\n    let conn_options: AnyConnectOptions = std::env::var(\"DATABASE_URL\")?.parse()?;\n\n    let last_meta = Arc::new(Mutex::new(None));\n    let last_meta_ = last_meta.clone();\n    let pool = AnyPoolOptions::new()\n        .max_lifetime(Duration::from_millis(400))\n        .min_connections(3)\n        .before_acquire(move |_conn, _meta| {\n            *last_meta_.lock().unwrap() = Some(_meta);\n            Box::pin(async { Ok(true) })\n        })\n        .connect_lazy_with(conn_options);\n\n    // Open and release 5 connections\n    let conns = vec![\n        pool.acquire().await?,\n        pool.acquire().await?,\n        pool.acquire().await?,\n        pool.acquire().await?,\n        pool.acquire().await?,\n    ];\n    assert_eq!(pool.size(), 5);\n    assert_eq!(pool.num_idle(), 0);\n    for mut conn in conns {\n        conn.return_to_pool().await;\n    }\n\n    assert_eq!(pool.size(), 5);\n    assert_eq!(pool.num_idle(), 5);\n\n    // Wait for at least two iterations of maintenance task\n    sqlx_core::rt::sleep(Duration::from_secs(1)).await;\n\n    // Existing connections should have been closed due to max lifetime\n    // and the pool should have reopened min_connections new ones.\n    // One connection might be in the process of being replaced so we assert 2-3.\n    assert!(\n        pool.size() >= 2 && pool.size() <= 3,\n        \"pool.size() = {}\",\n        pool.size()\n    );\n    for _ in 0..2 {\n        // Check that the connections was both acquired from the pool AND it's new\n        let _ = pool.acquire().await.expect(\"failed to acquire connection\");\n        let meta = last_meta\n            .lock()\n            .unwrap()\n            .take()\n            .expect(\"expected a connection from the pool\");\n        assert!(\n            meta.age < Duration::from_secs(2),\n            \"expected a fresh connection (age {:?})\",\n            meta.age\n        );\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/certs/.gitignore",
    "content": "# Certificate-signing request does not need to be committed\n*.csr\n# Test certificates aren't meant to be permanent, so tracking what serial number to use is unnecessary.\nca.srl\n"
  },
  {
    "path": "tests/certs/README.md",
    "content": "# SQLx Test TLS Certificates\n\nThis directory contains the following files for testing TLS connections.\n\n* `ca.crt`: Self-signed Certificate Authority for `client.crt`\n* `client.crt`: Client certificate signed by `ca.crt`\n* `server.crt`: Server certificate signed by `ca.crt`\n\nThese certificates are **not** to be used outside of testing with SQLx.\nThe private keys are publicly available in the `keys` directory.\n\nThese certificates should be valid until the year 2035.\n\nRusTLS requires TLS certificates to be x509v3. \nOpenSSL 3.2 and up create v3 certificates by default.\n\n## (Re)generating\n\nWhen generating certificates, OpenSSL prompts for a number of fields:\n\n```\nYou are about to be asked to enter information that will be incorporated\ninto your certificate request.\nWhat you are about to enter is what is called a Distinguished Name or a DN.\nThere are quite a few fields but you can leave some blank\nFor some fields there will be a default value,\nIf you enter '.', the field will be left blank.\n-----\nCountry Name (2 letter code) [AU]:\nState or Province Name (full name) [Some-State]:\nLocality Name (eg, city) []:\nOrganization Name (eg, company) [Internet Widgits Pty Ltd]:\nOrganizational Unit Name (eg, section) []:\nCommon Name (e.g. server FQDN or YOUR name) []:\nEmail Address []:\n```\n\nThese are purely informational and can _generally_ be left blank or filled with arbitrary values \n(except for `Common Name` with client certificates; see below for details).\n\n### CA Certificate\n\nCreate a self-signed root certificate:\n\n```shell\nopenssl req -x509 -sha256 -days 3650 -key keys/ca.key -out ca.crt\n```\n\nThis is passed as a trust root when testing certificate authentication.\n\n### Client Certificate\n\n**Note**: Postgres expects the Common Name (`CN`) field of the certificate to match the database username: \n<https://www.postgresql.org/docs/current/auth-cert.html>\n\nAt the prompt `Common Name (e.g. server FQDN or YOUR name) []:`, enter `postgres`.\n\nCreate a certificate signing request (CSR) to \"submit\" to our fake certificate authority:\n\n```\nopenssl req -key keys/client.key -new -out client.csr\n```\n\nCreate a signed certificate using our CA key and the CSR:\n\n```\nopenssl x509 -req -CA ca.crt -CAkey keys/ca.key -in client.csr -out client.crt -days 3650 -CAcreateserial\n```\n\n### Server Certificate\n\n\nCreate a certificate signing request (CSR) to \"submit\" to our fake certificate authority:\n\n```\nopenssl req -key keys/server.key -new -out server.csr -addext subjectAltName=DNS:sqlx.rs\n```\n\nThis adds a required x509 v3 extension:\n* `subjectAltName=DNS:sqlx.rs` supplies the Subject Alternative Name that RusTLS uses to verify the hostname.\n  * Only checked if using SSL mode `ssl_mode=verify_identity` (MySQL/MariaDB) or `sslmode=verify-full` (Postgres).\n\nCreate a signed certificate using our CA key and the CSR:\n\n```\nopenssl x509 -req -CA ca.crt -CAkey keys/ca.key -in server.csr -out server.crt -days 3650 -CAcreateserial\n```\n"
  },
  {
    "path": "tests/certs/ca.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIB0zCCAYWgAwIBAgIUEFN5G3AUb5d/ZC+q+YtFuMeoWvowBQYDK2VwMF8xCzAJ\nBgNVBAYTAnVzMRMwEQYDVQQIDApjYWxpZm9ybmlhMSEwHwYDVQQKDBhJbnRlcm5l\ndCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMMD0F1c3RpbiBCb25hbmRlcjAeFw0y\nNTA3MDEwMzA4MTVaFw0zNTA2MjkwMzA4MTVaMF8xCzAJBgNVBAYTAnVzMRMwEQYD\nVQQIDApjYWxpZm9ybmlhMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM\ndGQxGDAWBgNVBAMMD0F1c3RpbiBCb25hbmRlcjAqMAUGAytlcAMhAHfjdF5QJ4OW\nk/3XLlsxDcP8cwBVmB+ySWKq2JanRS8uo1MwUTAdBgNVHQ4EFgQUCw2pVpGKz2xk\nIjbVHYh0LnzdkW4wHwYDVR0jBBgwFoAUCw2pVpGKz2xkIjbVHYh0LnzdkW4wDwYD\nVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBA6VMDBPz9x0b5Wvw4D+2UrLdyhzzjqtrX\nUQOjCTqcKdEwWvgS6ftiQlQJPDfkVDEMOAJgqRmEGvsKjvwMCPIC\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "tests/certs/client.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBqjCCAVygAwIBAgIURmjYOsv10CRGeCFUY35KOsBmD8IwBQYDK2VwMF8xCzAJ\nBgNVBAYTAnVzMRMwEQYDVQQIDApjYWxpZm9ybmlhMSEwHwYDVQQKDBhJbnRlcm5l\ndCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAMMD0F1c3RpbiBCb25hbmRlcjAeFw0y\nNTA3MDEwNjQ2NDdaFw0zNTA2MjkwNjQ2NDdaMEcxCzAJBgNVBAYTAnVzMRMwEQYD\nVQQIDApjYWxpZm9ybmlhMRAwDgYDVQQKDAdTUUx4LnJzMREwDwYDVQQDDAhwb3N0\nZ3JlczAqMAUGAytlcAMhAKlX7AIHulcVhkBeSN2WtjZbjzde5tlUKwVWyWEhP7sE\no0IwQDAdBgNVHQ4EFgQUf2VV1eVj09YOwgKa1ZX1kq7VAd4wHwYDVR0jBBgwFoAU\nCw2pVpGKz2xkIjbVHYh0LnzdkW4wBQYDK2VwA0EA5WMQjRBwEI/QtLzSAQTy5fSM\nFGorJMxGtUpBjFzCEbYku4EHvbJoN707Kf9vYpgxjAIyP2cowxj/Wdd4paegBg==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "tests/certs/keys/ca.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEILnh8afwKgHjlFlCqooToMmzrI3DAifXtxhUtnCElFtn\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "tests/certs/keys/client.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICauTALD/rWma9h+oROYjcxDrzI9KZlaVzwmhiTpSItd\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "tests/certs/keys/server.key",
    "content": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIAbYyLPV13NEkja/UUn+MB00kdTMivtC9DFysTjtZOXb\n-----END PRIVATE KEY-----\n"
  },
  {
    "path": "tests/certs/server.crt",
    "content": "-----BEGIN CERTIFICATE-----\nMIIBnjCCAVCgAwIBAgIJALbHH0sRwKGPMAUGAytlcDBfMQswCQYDVQQGEwJ1czET\nMBEGA1UECAwKY2FsaWZvcm5pYTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ\ndHkgTHRkMRgwFgYDVQQDDA9BdXN0aW4gQm9uYW5kZXIwHhcNMjUwNzAxMDUyMTU2\nWhcNMzUwNjI5MDUyMTU2WjBGMQswCQYDVQQGEwJ1czETMBEGA1UECAwKY2FsaWZv\ncm5pYTEQMA4GA1UECgwHU1FMeC5yczEQMA4GA1UEAwwHc3FseC5yczAqMAUGAytl\ncAMhAA33S2qsqpZssUcYrpleMXDj5/mhb56HPaO3CIIgY5c8o0IwQDAdBgNVHQ4E\nFgQUPUpn95GHFuMe7+2pG5rbmJS55/wwHwYDVR0jBBgwFoAUCw2pVpGKz2xkIjbV\nHYh0LnzdkW4wBQYDK2VwA0EAExEOza9IrSchoQs1NwPxfCdfXMHiXpsgMThDuig+\n9hauW+b1KlBR3ZeW8AOIwazMhdstBFOhumaWPQ/wZNUkCg==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "tests/docker-compose.yml",
    "content": "services:\n    #\n    # MySQL 8.x, 5.7.x\n    # https://www.mysql.com/support/supportedplatforms/database.html\n    #\n\n    mysql_8:\n        image: mysql:8.0\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MYSQL_ROOT_HOST: '%'\n            MYSQL_ROOT_PASSWORD: password\n            MYSQL_DATABASE: sqlx\n\n    mysql_8_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: mysql:8.0\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MYSQL_ROOT_HOST: '%'\n            MYSQL_DATABASE: sqlx\n            MYSQL_ALLOW_EMPTY_PASSWORD: 1\n\n    mysql_5_7:\n        image: mysql:5.7\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MYSQL_ROOT_HOST: '%'\n            MYSQL_ROOT_PASSWORD: password\n            MYSQL_DATABASE: sqlx\n\n    mysql_5_7_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: mysql:5.7\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MYSQL_ROOT_HOST: '%'\n            MYSQL_DATABASE: sqlx\n            MYSQL_ALLOW_EMPTY_PASSWORD: 1\n\n    # MariaDB\n    # Testing will be dropped when Community Support ends.\n    # https://mariadb.org/about/#maintenance-policy\n\n    # EOL: 2028/06/04 (sooner than 11.4 for some reason)\n    mariadb_11_8:\n        image: mariadb:11.8\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_ROOT_PASSWORD: password\n            MARIADB_DATABASE: sqlx\n\n    mariadb_11_8_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: mariadb:11.8\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_DATABASE: sqlx\n            MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1\n\n    # EOL: 2029/05/29\n    mariadb_11_4:\n        image: mariadb:11.4\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_ROOT_PASSWORD: password\n            MARIADB_DATABASE: sqlx\n\n    mariadb_11_4_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: mariadb:11.4\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_DATABASE: sqlx\n            MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1\n\n    # EOL: 2028/02/16\n    mariadb_10_11:\n        image: mariadb:10.11\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_ROOT_PASSWORD: password\n            MARIADB_DATABASE: sqlx\n\n    mariadb_10_11_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: mariadb:10.11\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_DATABASE: sqlx\n            MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1\n\n    # EOL: 2026/07/06\n    mariadb_10_6:\n        image: mariadb:10.6\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            # UUID support was not added until 10.10\n            # - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_ROOT_PASSWORD: password\n            MARIADB_DATABASE: sqlx\n\n    mariadb_10_6_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: mariadb:10.6\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            # UUID support was not added until 10.10\n            # - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_DATABASE: sqlx\n            MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1\n\n    # Ensure MariaDB upstream isn't regressing before release\n    # https://mariadb.org/new-service-quay-io-mariadb-foundation-mariadb-devel/\n    mariadb_verylatest:\n        image: quay.io/mariadb-foundation/mariadb-devel:verylatest\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_ROOT_PASSWORD: password\n            MARIADB_DATABASE: sqlx\n\n    mariadb_verylatest_client_ssl:\n        build:\n            context: .\n            dockerfile: mysql/Dockerfile\n            args:\n                IMAGE: quay.io/mariadb-foundation/mariadb-devel:verylatest\n        volumes:\n            - \"./mysql/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n            - \"./mysql/setup-mariadb.sql:/docker-entrypoint-initdb.d/setup-mariadb.sql:z\"\n        ports:\n            - 3306\n        environment:\n            MARIADB_DATABASE: sqlx\n            MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: 1\n    #\n    # PostgreSQL 17.x, 16.x, 15.x, 14.x, 13.x\n    # https://www.postgresql.org/support/versioning/\n    #\n\n    postgres_17:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 17\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_USER: postgres\n            POSTGRES_PASSWORD: password\n            POSTGRES_HOST_AUTH_METHOD: scram-sha-256\n            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        # Loading `pg_stat_statements` should serve as a regression test for:\n        # https://github.com/launchbadge/sqlx/issues/2622\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c shared_preload_libraries=pg_stat_statements\n\n    postgres_17_client_ssl:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 17\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_HOST_AUTH_METHOD: trust\n            POSTGRES_INITDB_ARGS: --auth-host=trust\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf\n\n    postgres_16:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 16\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_USER: postgres\n            POSTGRES_PASSWORD: password\n            POSTGRES_HOST_AUTH_METHOD: scram-sha-256\n            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key\n\n    postgres_16_client_ssl:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 16\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_HOST_AUTH_METHOD: trust\n            POSTGRES_INITDB_ARGS: --auth-host=trust\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf\n\n    postgres_15:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 15\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_USER: postgres\n            POSTGRES_PASSWORD: password\n            POSTGRES_HOST_AUTH_METHOD: scram-sha-256\n            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key\n\n    postgres_15_client_ssl:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 15\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_HOST_AUTH_METHOD: trust\n            POSTGRES_INITDB_ARGS: --auth-host=trust\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf\n\n    postgres_14:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 14\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_USER: postgres\n            POSTGRES_PASSWORD: password\n            POSTGRES_HOST_AUTH_METHOD: scram-sha-256\n            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key\n\n    postgres_14_client_ssl:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 14\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_HOST_AUTH_METHOD: trust\n            POSTGRES_INITDB_ARGS: --auth-host=trust\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf\n\n    postgres_13:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 13\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_USER: postgres\n            POSTGRES_PASSWORD: password\n            POSTGRES_HOST_AUTH_METHOD: scram-sha-256\n            POSTGRES_INITDB_ARGS: --auth-host=scram-sha-256\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key\n\n    postgres_13_client_ssl:\n        build:\n            context: .\n            dockerfile: postgres/Dockerfile\n            args:\n                VERSION: 13\n        ports:\n            - 5432\n        environment:\n            POSTGRES_DB: sqlx\n            POSTGRES_HOST_AUTH_METHOD: trust\n            POSTGRES_INITDB_ARGS: --auth-host=trust\n        volumes:\n            - \"./postgres/setup.sql:/docker-entrypoint-initdb.d/setup.sql:z\"\n        command: >\n            -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key -c ssl_ca_file=/var/lib/postgresql/ca.crt -c hba_file=/var/lib/postgresql/pg_hba.conf\n"
  },
  {
    "path": "tests/docker.py",
    "content": "import subprocess\nimport sys\nimport time\nfrom os import path\nimport shutil\n\n# base dir of sqlx workspace\ndir_workspace = path.dirname(path.dirname(path.realpath(__file__)))\n\n# dir of tests\ndir_tests = path.join(dir_workspace, \"tests\")\n\n\n# start database server and return a URL to use to connect\ndef start_database(driver, database, cwd):\n    if driver == \"sqlite\":\n        database = path.join(cwd, database)\n        (base_path, ext) = path.splitext(database)\n        new_database = f\"{base_path}.test{ext}\"\n        if path.exists(database):\n            shutil.copy(database, new_database)\n        # short-circuit for sqlite\n        return f\"sqlite://{path.join(cwd, new_database)}?mode=rwc\"\n\n    res = subprocess.run(\n        [\"docker-compose\", \"up\", \"-d\", driver],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        cwd=dir_tests,\n    )\n\n    if res.returncode != 0:\n        print(res.stderr, file=sys.stderr)\n\n    if b\"done\" in res.stderr:\n        time.sleep(30)\n\n    # determine appropriate port for driver\n    if driver.startswith(\"mysql\") or driver.startswith(\"mariadb\"):\n        port = 3306\n\n    elif driver.startswith(\"postgres\"):\n        port = 5432\n\n    else:\n        raise NotImplementedError\n\n    # find port\n    res = subprocess.run(\n        [\"docker\", \"inspect\", f\"-f='{{{{(index (index .NetworkSettings.Ports \\\"{port}/tcp\\\") 0).HostPort}}}}'\",\n         f\"sqlx_{driver}_1\"],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        cwd=dir_tests,\n    )\n\n    if res.returncode != 0:\n        print(res.stderr, file=sys.stderr)\n\n    port = int(res.stdout[1:-2].decode())\n\n    # need additional permissions to connect to MySQL when using SSL\n    res = subprocess.run(\n        [\"docker\", \"exec\", f\"sqlx_{driver}_1\", \"mysql\", \"-u\", \"root\", \"-e\", \"GRANT ALL PRIVILEGES ON *.* TO 'root' WITH GRANT OPTION;\"],\n        stdout=subprocess.PIPE,\n        stderr=subprocess.PIPE,\n        cwd=dir_tests,\n    )\n\n    if res.returncode != 0:\n        print(res.stderr, file=sys.stderr)\n\n    # do not set password in URL if authenticating using SSL key file\n    if driver.endswith(\"client_ssl\"):\n        password = \"\"\n    else:\n        password = \":password\"\n\n    # construct appropriate database URL\n    if driver.startswith(\"mysql\") or driver.startswith(\"mariadb\"):\n        return f\"mysql://root{password}@localhost:{port}/{database}\"\n\n    elif driver.startswith(\"postgres\"):\n        return f\"postgres://postgres{password}@localhost:{port}/{database}\"\n\n    else:\n        raise NotImplementedError\n"
  },
  {
    "path": "tests/fixtures/mysql/posts.sql",
    "content": "insert into post(post_id, user_id, content, created_at)\nvalues (1,\n        1,\n        'This new computer is lightning-fast!',\n        timestamp(now(), '-1:00:00')),\n       (2,\n        2,\n        '@alice is a haxxor :(',\n        timestamp(now(), '-0:30:00'));\n"
  },
  {
    "path": "tests/fixtures/mysql/users.sql",
    "content": "insert into user(user_id, username)\nvalues (1, 'alice'), (2, 'bob');\n"
  },
  {
    "path": "tests/fixtures/postgres/posts.sql",
    "content": "insert into post(post_id, user_id, content, created_at)\nvalues\n       (\n        '252c1d98-a9b0-4f18-8298-e59058bdfe16',\n        '6592b7c0-b531-4613-ace5-94246b7ce0c3',\n        'This new computer is lightning-fast!',\n        now() + '1 hour ago'::interval\n        ),\n       (\n        '844265f7-2472-4689-9a2e-b21f40dbf401',\n        '6592b7c0-b531-4613-ace5-94246b7ce0c3',\n        '@alice is a haxxor :(',\n        now() + '30 minutes ago'::interval\n        );\n"
  },
  {
    "path": "tests/fixtures/postgres/users.sql",
    "content": "insert into \"user\"(user_id, username)\nvalues ('6592b7c0-b531-4613-ace5-94246b7ce0c3', 'alice'), ('297923c5-a83c-4052-bab0-030887154e52', 'bob');\n"
  },
  {
    "path": "tests/migrate/macro.rs",
    "content": "#![cfg(unix)]\nuse sqlx::migrate::Migrator;\nuse std::path::Path;\n\nstatic EMBEDDED_SIMPLE: Migrator = sqlx::migrate!(\"tests/migrate/migrations_simple\");\nstatic EMBEDDED_REVERSIBLE: Migrator = sqlx::migrate!(\"tests/migrate/migrations_reversible\");\nstatic EMBEDDED_SYMLINK: Migrator = sqlx::migrate!(\"tests/migrate/migrations_symlink\");\n\n#[sqlx_macros::test]\nasync fn same_output() -> anyhow::Result<()> {\n    let runtime_simple = Migrator::new(Path::new(\"tests/migrate/migrations_simple\")).await?;\n    let runtime_reversible =\n        Migrator::new(Path::new(\"tests/migrate/migrations_reversible\")).await?;\n    let runtime_symlink = Migrator::new(Path::new(\"tests/migrate/migrations_symlink\")).await?;\n\n    assert_same(&EMBEDDED_SIMPLE, &runtime_simple);\n    assert_same(&EMBEDDED_REVERSIBLE, &runtime_reversible);\n    assert_same(&EMBEDDED_SYMLINK, &runtime_symlink);\n\n    Ok(())\n}\n\nfn assert_same(embedded: &Migrator, runtime: &Migrator) {\n    assert_eq!(runtime.migrations.len(), embedded.migrations.len());\n\n    for (e, r) in embedded.iter().zip(runtime.iter()) {\n        assert_eq!(e.version, r.version);\n        assert_eq!(e.description, r.description);\n        assert_eq!(e.migration_type, r.migration_type);\n        assert_eq!(e.sql, r.sql);\n        assert_eq!(e.checksum, r.checksum);\n    }\n}\n"
  },
  {
    "path": "tests/migrate/migrations_reversible/20220721124650_add_table.down.sql",
    "content": "DROP TABLE migrations_reversible_test;\n"
  },
  {
    "path": "tests/migrate/migrations_reversible/20220721124650_add_table.up.sql",
    "content": "CREATE TABLE migrations_reversible_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_reversible_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/migrate/migrations_reversible/20220721125033_modify_column.down.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload - 1;\n"
  },
  {
    "path": "tests/migrate/migrations_reversible/20220721125033_modify_column.up.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload + 1;\n"
  },
  {
    "path": "tests/migrate/migrations_simple/20220721115250_add_test_table.sql",
    "content": "CREATE TABLE migrations_simple_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_simple_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/migrate/migrations_simple/20220721115524_convert_type.sql",
    "content": "-- Perform a tricky conversion of the payload.\n--\n-- This script will only succeed once and will fail if executed twice.\n\n-- set up temporary target column\nALTER TABLE migrations_simple_test\nADD some_payload_tmp TEXT;\n\n-- perform conversion\n-- This will fail if `some_payload` is already a string column due to the addition.\n-- We add a suffix after the addition to ensure that the SQL database does not silently cast the string back to an \n-- integer.\nUPDATE migrations_simple_test\nSET some_payload_tmp = CONCAT(CAST((some_payload + 10) AS TEXT), '_suffix');\n\n-- remove original column including the content\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload;\n\n-- prepare new payload column (nullable, so we can copy over the data)\nALTER TABLE migrations_simple_test\nADD some_payload TEXT;\n\n-- copy new values\nUPDATE migrations_simple_test\nSET some_payload = some_payload_tmp;\n\n-- \"freeze\" column\nALTER TABLE migrations_simple_test\nALTER COLUMN some_payload SET NOT NULL;\n\n-- clean up\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload_tmp;\n"
  },
  {
    "path": "tests/mssql/Dockerfile",
    "content": "ARG VERSION\nFROM mcr.microsoft.com/mssql/server:${VERSION}\n\n# Create a config directory\nRUN mkdir -p /usr/config\nWORKDIR /usr/config\n\n# Bundle config source\nCOPY mssql/entrypoint.sh /usr/config/entrypoint.sh\nCOPY mssql/configure-db.sh /usr/config/configure-db.sh\nCOPY mssql/setup.sql /usr/config/setup.sql\n\n# Grant permissions for to our scripts to be executable\nUSER root\nRUN chmod +x /usr/config/entrypoint.sh\nRUN chmod +x /usr/config/configure-db.sh\nRUN chown 10001 /usr/config/entrypoint.sh\nRUN chown 10001 /usr/config/configure-db.sh\nUSER 10001\n\nENTRYPOINT [\"/usr/config/entrypoint.sh\"]\n"
  },
  {
    "path": "tests/mssql/configure-db.sh",
    "content": "#!/usr/bin/env bash\n\n# Wait 60 seconds for SQL Server to start up\nsleep 60\n\n# Run the setup script to create the DB and the schema in the DB\n/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -d master -i setup.sql\n"
  },
  {
    "path": "tests/mssql/describe.rs",
    "content": "use sqlx::mssql::Mssql;\nuse sqlx::{Column, Executor, TypeInfo};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_describes_simple() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let d = conn.describe(\"SELECT * FROM tweet\").await?;\n\n    assert_eq!(d.columns()[0].name(), \"id\");\n    assert_eq!(d.columns()[1].name(), \"text\");\n    assert_eq!(d.columns()[2].name(), \"is_sent\");\n    assert_eq!(d.columns()[3].name(), \"owner_id\");\n\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.nullable(1), Some(false));\n    assert_eq!(d.nullable(2), Some(false));\n    assert_eq!(d.nullable(3), Some(true));\n\n    assert_eq!(d.columns()[0].type_info().name(), \"BIGINT\");\n    assert_eq!(d.columns()[1].type_info().name(), \"NVARCHAR\");\n    assert_eq!(d.columns()[2].type_info().name(), \"TINYINT\");\n    assert_eq!(d.columns()[3].type_info().name(), \"BIGINT\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_with_params() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let d = conn\n        .describe(\"SELECT text FROM tweet WHERE id = @p1\")\n        .await?;\n\n    assert_eq!(d.columns()[0].name(), \"text\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mssql/entrypoint.sh",
    "content": "#!/usr/bin/env bash\n\n# Start the script to create the DB and user\n/usr/config/configure-db.sh &\n\n# Start SQL Server\n/opt/mssql/bin/sqlservr\n"
  },
  {
    "path": "tests/mssql/macros.rs",
    "content": "use sqlx::Mssql;\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn test_query_simple() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let account =\n        sqlx::query!(\"select * from (select (1) as id, 'Herp Derpinson' as name, cast(null as char) as email, CAST(1 as bit) as deleted) accounts\")\n            .fetch_one(&mut conn)\n            .await?;\n\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, \"Herp Derpinson\");\n    assert_eq!(account.email, None);\n    assert_eq!(account.deleted, Some(true));\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mssql/mssql-2017.dockerfile",
    "content": "# vim: set ft=dockerfile:\nARG VERSION\nFROM mcr.microsoft.com/mssql/server:${VERSION}\n\n# Create a config directory\nRUN mkdir -p /usr/config\nWORKDIR /usr/config\n\n# Bundle config source\nCOPY mssql/entrypoint.sh /usr/config/entrypoint.sh\nCOPY mssql/configure-db.sh /usr/config/configure-db.sh\nCOPY mssql/setup.sql /usr/config/setup.sql\n\n# Grant permissions for to our scripts to be executable\nUSER root\nRUN chmod +x /usr/config/entrypoint.sh\nRUN chmod +x /usr/config/configure-db.sh\n\nENTRYPOINT [\"/usr/config/entrypoint.sh\"]\n"
  },
  {
    "path": "tests/mssql/mssql.rs",
    "content": "use futures_util::TryStreamExt;\nuse sqlx::mssql::{Mssql, MssqlPoolOptions};\nuse sqlx::{Column, Connection, Executor, MssqlConnection, Row, Statement, TypeInfo};\nuse sqlx_core::mssql::MssqlRow;\nuse sqlx_test::new;\nuse std::sync::atomic::{AtomicI32, Ordering};\nuse std::time::Duration;\n\n#[sqlx_macros::test]\nasync fn it_connects() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    conn.ping().await?;\n\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_select_expression() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let row: MssqlRow = conn.fetch_one(\"SELECT 4\").await?;\n    let v: i32 = row.try_get(0)?;\n\n    assert_eq!(v, 4);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_select_expression_by_name() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let row: MssqlRow = conn.fetch_one(\"SELECT 4 as _3\").await?;\n    let v: i32 = row.try_get(\"_3\")?;\n\n    assert_eq!(v, 4);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fail_to_connect() -> anyhow::Result<()> {\n    let mut url = dotenvy::var(\"DATABASE_URL\")?;\n    url = url.replace(\"Password\", \"NotPassword\");\n\n    let res = MssqlConnection::connect(&url).await;\n    let err = res.unwrap_err();\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.message(), \"Login failed for user \\'sa\\'.\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_inspect_errors() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"select f\").execute(&mut conn).await;\n    let err = res.unwrap_err();\n\n    // can also do [as_database_error] or use `match ..`\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.message(), \"Invalid column name 'f'.\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_maths() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let value = sqlx::query(\"SELECT 1 + @p1\")\n        .bind(5_i32)\n        .try_map(|row: MssqlRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(6_i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TABLE #users (id INTEGER PRIMARY KEY);\n            \"#,\n        )\n        .await?;\n\n    for index in 1..=10_i32 {\n        let done = sqlx::query(\"INSERT INTO #users (id) VALUES (@p1)\")\n            .bind(index * 2)\n            .execute(&mut conn)\n            .await?;\n\n        assert_eq!(done.rows_affected(), 1);\n    }\n\n    let sum: i32 = sqlx::query(\"SELECT id FROM #users\")\n        .try_map(|row: MssqlRow| row.try_get::<i32, _>(0))\n        .fetch(&mut conn)\n        .try_fold(0_i32, |acc, x| async move { Ok(acc + x) })\n        .await?;\n\n    assert_eq!(sum, 110);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_return_1000_rows() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TABLE #users (id INTEGER PRIMARY KEY);\n            \"#,\n        )\n        .await?;\n\n    for index in 1..=1000_i32 {\n        let done = sqlx::query(\"INSERT INTO #users (id) VALUES (@p1)\")\n            .bind(index * 2)\n            .execute(&mut conn)\n            .await?;\n\n        assert_eq!(done.rows_affected(), 1);\n    }\n\n    let sum: i32 = sqlx::query(\"SELECT id FROM #users\")\n        .try_map(|row: MssqlRow| row.try_get::<i32, _>(0))\n        .fetch(&mut conn)\n        .try_fold(0_i32, |acc, x| async move { Ok(acc + x) })\n        .await?;\n\n    assert_eq!(sum, 1001000);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_selects_null() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let (_, val): (i32, Option<i32>) = sqlx::query_as(\"SELECT 5, NULL\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert!(val.is_none());\n\n    let val: Option<i32> = conn.fetch_one(\"SELECT 10, NULL\").await?.try_get(1)?;\n\n    assert!(val.is_none());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_binds_empty_string_and_null() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    let (val, val2): (String, Option<String>) = sqlx::query_as(\"SELECT @p1, @p2\")\n        .bind(\"\")\n        .bind(None::<String>)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert!(val.is_empty());\n    assert!(val2.is_none());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_work_with_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    conn.execute(\"IF OBJECT_ID('_sqlx_users_1922', 'U') IS NULL CREATE TABLE _sqlx_users_1922 (id INTEGER PRIMARY KEY)\")\n        .await?;\n\n    conn.execute(\"DELETE FROM _sqlx_users_1922\").await?;\n\n    // begin .. rollback\n\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO _sqlx_users_1922 (id) VALUES ($1)\")\n        .bind(10_i32)\n        .execute(&mut tx)\n        .await?;\n\n    tx.rollback().await?;\n\n    let (count,): (i32,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_1922\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 0);\n\n    // begin .. commit\n\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO _sqlx_users_1922 (id) VALUES (@p1)\")\n        .bind(10_i32)\n        .execute(&mut tx)\n        .await?;\n\n    tx.commit().await?;\n\n    let (count,): (i32,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_1922\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    // begin .. (drop)\n\n    {\n        let mut tx = conn.begin().await?;\n\n        sqlx::query(\"INSERT INTO _sqlx_users_1922 (id) VALUES (@p1)\")\n            .bind(20_i32)\n            .execute(&mut tx)\n            .await?;\n    }\n\n    conn = new::<Mssql>().await?;\n\n    let (count,): (i32,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_1922\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_work_with_nested_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n\n    conn.execute(\"IF OBJECT_ID('_sqlx_users_2523', 'U') IS NULL CREATE TABLE _sqlx_users_2523 (id INTEGER PRIMARY KEY)\")\n        .await?;\n\n    conn.execute(\"DELETE FROM _sqlx_users_2523\").await?;\n\n    // begin\n    let mut tx = conn.begin().await?;\n\n    // insert a user\n    sqlx::query(\"INSERT INTO _sqlx_users_2523 (id) VALUES (@p1)\")\n        .bind(50_i32)\n        .execute(&mut tx)\n        .await?;\n\n    // begin once more\n    let mut tx2 = tx.begin().await?;\n\n    // insert another user\n    sqlx::query(\"INSERT INTO _sqlx_users_2523 (id) VALUES (@p1)\")\n        .bind(10_i32)\n        .execute(&mut tx2)\n        .await?;\n\n    // never mind, rollback\n    tx2.rollback().await?;\n\n    // did we really?\n    let (count,): (i32,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_2523\")\n        .fetch_one(&mut tx)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    // actually, commit\n    tx.commit().await?;\n\n    // did we really?\n    let (count,): (i32,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_2523\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_prepare_then_execute() -> anyhow::Result<()> {\n    let mut conn = new::<Mssql>().await?;\n    let mut tx = conn.begin().await?;\n\n    let tweet_id: i64 = sqlx::query_scalar(\n        \"INSERT INTO tweet ( id, text ) OUTPUT INSERTED.id VALUES ( 50, 'Hello, World' )\",\n    )\n    .fetch_one(&mut tx)\n    .await?;\n\n    let statement = tx.prepare(\"SELECT * FROM tweet WHERE id = @p1\").await?;\n\n    assert_eq!(statement.column(0).name(), \"id\");\n    assert_eq!(statement.column(1).name(), \"text\");\n    assert_eq!(statement.column(2).name(), \"is_sent\");\n    assert_eq!(statement.column(3).name(), \"owner_id\");\n\n    assert_eq!(statement.column(0).type_info().name(), \"BIGINT\");\n    assert_eq!(statement.column(1).type_info().name(), \"NVARCHAR\");\n    assert_eq!(statement.column(2).type_info().name(), \"TINYINT\");\n    assert_eq!(statement.column(3).type_info().name(), \"BIGINT\");\n\n    let row = statement.query().bind(tweet_id).fetch_one(&mut tx).await?;\n    let tweet_text: String = row.try_get(\"text\")?;\n\n    assert_eq!(tweet_text, \"Hello, World\");\n\n    Ok(())\n}\n\n// MSSQL-specific copy of the test case in `tests/any/pool.rs`\n// because MSSQL has its own bespoke syntax for temporary tables.\n#[sqlx_macros::test]\nasync fn test_pool_callbacks() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n    struct ConnStats {\n        id: i32,\n        before_acquire_calls: i32,\n        after_release_calls: i32,\n    }\n\n    sqlx_test::setup_if_needed();\n\n    let current_id = AtomicI32::new(0);\n\n    let pool = MssqlPoolOptions::new()\n        .max_connections(1)\n        .acquire_timeout(Duration::from_secs(5))\n        .after_connect(move |conn, meta| {\n            assert_eq!(meta.age, Duration::ZERO);\n            assert_eq!(meta.idle_for, Duration::ZERO);\n\n            let id = current_id.fetch_add(1, Ordering::AcqRel);\n\n            Box::pin(async move {\n                let statement = format!(\n                    // language=MSSQL\n                    r#\"\n                    CREATE TABLE #conn_stats(\n                        id int primary key,\n                        before_acquire_calls int default 0,\n                        after_release_calls int default 0 \n                    );\n                    INSERT INTO #conn_stats(id) VALUES ({});\n                    \"#,\n                    // Until we have generalized bind parameters\n                    id\n                );\n\n                conn.execute(&statement[..]).await?;\n                Ok(())\n            })\n        })\n        .before_acquire(|conn, meta| {\n            // `age` and `idle_for` should both be nonzero\n            assert_ne!(meta.age, Duration::ZERO);\n            assert_ne!(meta.idle_for, Duration::ZERO);\n\n            Box::pin(async move {\n                // MSSQL doesn't support UPDATE ... RETURNING either\n                sqlx::query(\n                    r#\"\n                        UPDATE #conn_stats \n                        SET before_acquire_calls = before_acquire_calls + 1\n                    \"#,\n                )\n                .execute(&mut *conn)\n                .await?;\n\n                let stats: ConnStats = sqlx::query_as(\"SELECT * FROM #conn_stats\")\n                    .fetch_one(conn)\n                    .await?;\n\n                // For even IDs, cap by the number of before_acquire calls.\n                // Ignore the check for odd IDs.\n                Ok((stats.id & 1) == 1 || stats.before_acquire_calls < 3)\n            })\n        })\n        .after_release(|conn, meta| {\n            // `age` should be nonzero but `idle_for` should be zero.\n            assert_ne!(meta.age, Duration::ZERO);\n            assert_eq!(meta.idle_for, Duration::ZERO);\n\n            Box::pin(async move {\n                sqlx::query(\n                    r#\"\n                        UPDATE #conn_stats \n                        SET after_release_calls = after_release_calls + 1\n                    \"#,\n                )\n                .execute(&mut *conn)\n                .await?;\n\n                let stats: ConnStats = sqlx::query_as(\"SELECT * FROM #conn_stats\")\n                    .fetch_one(conn)\n                    .await?;\n\n                // For odd IDs, cap by the number of before_release calls.\n                // Ignore the check for even IDs.\n                Ok((stats.id & 1) == 0 || stats.after_release_calls < 4)\n            })\n        })\n        // Don't establish a connection yet.\n        .connect_lazy(&std::env::var(\"DATABASE_URL\")?)?;\n\n    // Expected pattern of (id, before_acquire_calls, after_release_calls)\n    let pattern = [\n        // The connection pool starts empty.\n        (0, 0, 0),\n        (0, 1, 1),\n        (0, 2, 2),\n        (1, 0, 0),\n        (1, 1, 1),\n        (1, 2, 2),\n        // We should expect one more `acquire` because the ID is odd\n        (1, 3, 3),\n        (2, 0, 0),\n        (2, 1, 1),\n        (2, 2, 2),\n        (3, 0, 0),\n    ];\n\n    for (id, before_acquire_calls, after_release_calls) in pattern {\n        let conn_stats: ConnStats = sqlx::query_as(\"SELECT * FROM #conn_stats\")\n            .fetch_one(&pool)\n            .await?;\n\n        assert_eq!(\n            conn_stats,\n            ConnStats {\n                id,\n                before_acquire_calls,\n                after_release_calls\n            }\n        );\n    }\n\n    pool.close().await;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mssql/setup.sql",
    "content": "IF DB_ID('sqlx') IS NULL\n    BEGIN\n        CREATE DATABASE sqlx;\n    END;\nGO\n\nUSE sqlx;\nGO\n\nIF OBJECT_ID('tweet') IS NULL\n    BEGIN\n        CREATE TABLE tweet\n        (\n            id       BIGINT          NOT NULL PRIMARY KEY,\n            text     NVARCHAR(4000)  NOT NULL,\n            is_sent  TINYINT         NOT NULL DEFAULT 1,\n            owner_id BIGINT\n        );\n    END;\nGO\n"
  },
  {
    "path": "tests/mssql/types.rs",
    "content": "use sqlx::mssql::Mssql;\nuse sqlx_test::test_type;\n\ntest_type!(null<Option<i32>>(Mssql,\n    \"CAST(NULL as INT)\" == None::<i32>\n));\n\ntest_type!(u8(\n    Mssql,\n    \"CAST(5 AS TINYINT)\" == 5_u8,\n    \"CAST(0 AS TINYINT)\" == 0_u8,\n    \"CAST(255 AS TINYINT)\" == 255_u8,\n));\n\ntest_type!(i8(\n    Mssql,\n    \"CAST(5 AS TINYINT)\" == 5_i8,\n    \"CAST(0 AS TINYINT)\" == 0_i8\n));\n\ntest_type!(i16(Mssql, \"CAST(21415 AS SMALLINT)\" == 21415_i16));\n\ntest_type!(i32(Mssql, \"CAST(2141512 AS INT)\" == 2141512_i32));\n\ntest_type!(i64(Mssql, \"CAST(32324324432 AS BIGINT)\" == 32324324432_i64));\n\ntest_type!(f32(\n    Mssql,\n    \"CAST(3.1410000324249268 AS REAL)\" == 3.141f32 as f64 as f32\n));\n\ntest_type!(f64(\n    Mssql,\n    \"CAST(939399419.1225182 AS FLOAT)\" == 939399419.1225182_f64\n));\n\ntest_type!(str_nvarchar<String>(Mssql,\n    \"CAST('this is foo' as NVARCHAR)\" == \"this is foo\",\n));\n\ntest_type!(str<String>(Mssql,\n    \"'this is foo'\" == \"this is foo\",\n    \"''\" == \"\",\n));\n\ntest_type!(bool(\n    Mssql,\n    \"CAST(1 as BIT)\" == true,\n    \"CAST(0 as BIT)\" == false\n));\n"
  },
  {
    "path": "tests/mysql/Dockerfile",
    "content": "ARG IMAGE\nFROM ${IMAGE}\n\n# Copy SSL certificate (and key)\nCOPY certs/server.crt /etc/mysql/ssl/server.crt\nCOPY certs/ca.crt /etc/mysql/ssl/ca.crt\nCOPY certs/keys/server.key /etc/mysql/ssl/server.key\nCOPY mysql/my.cnf /etc/mysql/my.cnf\n\n# Fix permissions\nRUN chown mysql:mysql /etc/mysql/ssl/server.crt /etc/mysql/ssl/server.key\nRUN chmod 0600 /etc/mysql/ssl/server.crt /etc/mysql/ssl/server.key\n\n# Create dir for secure-file-priv\nRUN mkdir -p /var/lib/mysql-files\n"
  },
  {
    "path": "tests/mysql/derives.rs",
    "content": "use sqlx_mysql::MySql;\nuse sqlx_test::{new, test_type};\n\n#[sqlx::test]\nasync fn test_derive_strong_enum() -> anyhow::Result<()> {\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"PascalCase\")]\n    enum PascalCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"camelCase\")]\n    enum CamelCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"snake_case\")]\n    enum SnakeCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"SCREAMING_SNAKE_CASE\")]\n    enum ScreamingSnakeCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"kebab-case\")]\n    enum KebabCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"lowercase\")]\n    enum LowerCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    #[sqlx(rename_all = \"UPPERCASE\")]\n    enum UpperCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::Type, PartialEq, Eq, Debug)]\n    enum DefaultCaseEnum {\n        FooFoo,\n        BarBar,\n        BazBaz,\n    }\n\n    #[derive(sqlx::FromRow, PartialEq, Eq, Debug)]\n    struct StrongEnumRow {\n        pascal_case: PascalCaseEnum,\n        camel_case: CamelCaseEnum,\n        snake_case: SnakeCaseEnum,\n        screaming_snake_case: ScreamingSnakeCaseEnum,\n        kebab_case: KebabCaseEnum,\n        lowercase: LowerCaseEnum,\n        uppercase: UpperCaseEnum,\n        default_case: DefaultCaseEnum,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    sqlx::raw_sql(\n        r#\"\n            CREATE TEMPORARY TABLE strong_enum (\n                pascal_case ENUM('FooFoo', 'BarBar', 'BazBaz'),\n                camel_case ENUM('fooFoo', 'barBar', 'bazBaz'),\n                snake_case ENUM('foo_foo', 'bar_bar', 'baz_baz'),\n                screaming_snake_case ENUM('FOO_FOO', 'BAR_BAR', 'BAZ_BAZ'),\n                kebab_case ENUM('foo-foo', 'bar-bar', 'baz-baz'),\n                lowercase ENUM('foofoo', 'barbar', 'bazbaz'),\n                uppercase ENUM('FOOFOO', 'BARBAR', 'BAZBAZ'),\n                default_case ENUM('FooFoo', 'BarBar', 'BazBaz')\n            );\n        \"#,\n    )\n    .execute(&mut conn)\n    .await?;\n\n    let input = StrongEnumRow {\n        pascal_case: PascalCaseEnum::FooFoo,\n        camel_case: CamelCaseEnum::BarBar,\n        snake_case: SnakeCaseEnum::BazBaz,\n        screaming_snake_case: ScreamingSnakeCaseEnum::FooFoo,\n        kebab_case: KebabCaseEnum::BarBar,\n        lowercase: LowerCaseEnum::BazBaz,\n        uppercase: UpperCaseEnum::FooFoo,\n        default_case: DefaultCaseEnum::BarBar,\n    };\n\n    sqlx::query(\n        r#\"\n            INSERT INTO strong_enum(\n                pascal_case,\n                camel_case,\n                snake_case,\n                screaming_snake_case,\n                kebab_case,\n                lowercase,\n                uppercase,\n                default_case\n            )\n            VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n        \"#,\n    )\n    .bind(&input.pascal_case)\n    .bind(&input.camel_case)\n    .bind(&input.snake_case)\n    .bind(&input.screaming_snake_case)\n    .bind(&input.kebab_case)\n    .bind(&input.lowercase)\n    .bind(&input.uppercase)\n    .bind(&input.default_case)\n    .execute(&mut conn)\n    .await?;\n\n    let output: StrongEnumRow = sqlx::query_as(\"SELECT * FROM strong_enum\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(input, output);\n\n    Ok(())\n}\n\n#[sqlx::test]\nasync fn test_derive_weak_enum() -> anyhow::Result<()> {\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(i8)]\n    enum WeakEnumI8 {\n        Foo = i8::MIN,\n        Bar = 0,\n        Baz = i8::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(i16)]\n    enum WeakEnumI16 {\n        Foo = i16::MIN,\n        Bar = 0,\n        Baz = i16::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(i32)]\n    enum WeakEnumI32 {\n        Foo = i32::MIN,\n        Bar = 0,\n        Baz = i32::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(i64)]\n    enum WeakEnumI64 {\n        Foo = i64::MIN,\n        Bar = 0,\n        Baz = i64::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(u8)]\n    enum WeakEnumU8 {\n        Foo = 0,\n        Bar = 1,\n        Baz = u8::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(u16)]\n    enum WeakEnumU16 {\n        Foo = 0,\n        Bar = 1,\n        Baz = u16::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(u32)]\n    enum WeakEnumU32 {\n        Foo = 0,\n        Bar = 1,\n        Baz = u32::MAX,\n    }\n\n    #[derive(sqlx::Type, Debug, PartialEq, Eq)]\n    #[repr(u64)]\n    enum WeakEnumU64 {\n        Foo = 0,\n        Bar = 1,\n        Baz = u64::MAX,\n    }\n\n    #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n    struct WeakEnumRow {\n        i8: WeakEnumI8,\n        i16: WeakEnumI16,\n        i32: WeakEnumI32,\n        i64: WeakEnumI64,\n        u8: WeakEnumU8,\n        u16: WeakEnumU16,\n        u32: WeakEnumU32,\n        u64: WeakEnumU64,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    sqlx::raw_sql(\n        r#\"\n            CREATE TEMPORARY TABLE weak_enum (\n                i8 TINYINT,\n                i16 SMALLINT,\n                i32 INT,\n                i64 BIGINT,\n                u8 TINYINT UNSIGNED,\n                u16 SMALLINT UNSIGNED,\n                u32 INT UNSIGNED,\n                u64 BIGINT UNSIGNED\n            )\n        \"#,\n    )\n    .execute(&mut conn)\n    .await?;\n\n    let rows_in = vec![\n        WeakEnumRow {\n            i8: WeakEnumI8::Foo,\n            i16: WeakEnumI16::Foo,\n            i32: WeakEnumI32::Foo,\n            i64: WeakEnumI64::Foo,\n            u8: WeakEnumU8::Foo,\n            u16: WeakEnumU16::Foo,\n            u32: WeakEnumU32::Foo,\n            u64: WeakEnumU64::Foo,\n        },\n        WeakEnumRow {\n            i8: WeakEnumI8::Bar,\n            i16: WeakEnumI16::Bar,\n            i32: WeakEnumI32::Bar,\n            i64: WeakEnumI64::Bar,\n            u8: WeakEnumU8::Bar,\n            u16: WeakEnumU16::Bar,\n            u32: WeakEnumU32::Bar,\n            u64: WeakEnumU64::Bar,\n        },\n        WeakEnumRow {\n            i8: WeakEnumI8::Baz,\n            i16: WeakEnumI16::Baz,\n            i32: WeakEnumI32::Baz,\n            i64: WeakEnumI64::Baz,\n            u8: WeakEnumU8::Baz,\n            u16: WeakEnumU16::Baz,\n            u32: WeakEnumU32::Baz,\n            u64: WeakEnumU64::Baz,\n        },\n    ];\n\n    for row in &rows_in {\n        sqlx::query(\n            r#\"\n                INSERT INTO weak_enum(i8, i16, i32, i64, u8, u16, u32, u64)\n                VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n            \"#,\n        )\n        .bind(&row.i8)\n        .bind(&row.i16)\n        .bind(&row.i32)\n        .bind(&row.i64)\n        .bind(&row.u8)\n        .bind(&row.u16)\n        .bind(&row.u32)\n        .bind(&row.u64)\n        .execute(&mut conn)\n        .await?;\n    }\n\n    let rows_out: Vec<WeakEnumRow> = sqlx::query_as(\"SELECT * FROM weak_enum\")\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(rows_in, rows_out);\n\n    Ok(())\n}\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct TransparentTuple(i64);\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct TransparentNamed {\n    field: i64,\n}\n\ntest_type!(transparent_tuple<TransparentTuple>(MySql,\n    \"0\" == TransparentTuple(0),\n    \"23523\" == TransparentTuple(23523)\n));\n\ntest_type!(transparent_named<TransparentNamed>(MySql,\n    \"0\" == TransparentNamed { field: 0 },\n    \"23523\" == TransparentNamed { field: 23523 },\n));\n"
  },
  {
    "path": "tests/mysql/describe.rs",
    "content": "use sqlx::mysql::MySql;\nuse sqlx::{Column, Executor, SqlSafeStr, Type, TypeInfo};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_describes_simple() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let d = conn.describe(\"SELECT * FROM tweet\".into_sql_str()).await?;\n\n    assert_eq!(d.columns()[0].name(), \"id\");\n    assert_eq!(d.columns()[1].name(), \"created_at\");\n    assert_eq!(d.columns()[2].name(), \"text\");\n    assert_eq!(d.columns()[3].name(), \"owner_id\");\n\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.nullable(1), Some(false));\n    assert_eq!(d.nullable(2), Some(false));\n    assert_eq!(d.nullable(3), Some(true));\n\n    assert_eq!(d.columns()[0].type_info().name(), \"BIGINT\");\n    assert_eq!(d.columns()[1].type_info().name(), \"TIMESTAMP\");\n    assert_eq!(d.columns()[2].type_info().name(), \"TEXT\");\n    assert_eq!(d.columns()[3].type_info().name(), \"BIGINT\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_boolean() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    conn.execute(\n        r#\"\nCREATE TEMPORARY TABLE with_bit_and_tinyint (\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    value_bit_1 BIT(1),\n    value_bool BOOLEAN,\n    bit_n BIT(64),\n    value_int TINYINT\n);\n    \"#,\n    )\n    .await?;\n\n    let d = conn\n        .describe(\"SELECT * FROM with_bit_and_tinyint\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.column(2).name(), \"value_bool\");\n    assert_eq!(d.column(2).type_info().name(), \"BOOLEAN\");\n\n    assert_eq!(d.column(1).name(), \"value_bit_1\");\n    assert_eq!(d.column(1).type_info().name(), \"BIT\");\n\n    assert!(<bool as Type<MySql>>::compatible(&d.column(1).type_info()));\n    assert!(<bool as Type<MySql>>::compatible(&d.column(2).type_info()));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn uses_alias_name() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let d = conn\n        .describe(\"SELECT text AS tweet_text FROM tweet\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns()[0].name(), \"tweet_text\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mysql/error.rs",
    "content": "use sqlx::{error::ErrorKind, mysql::MySql, Connection, Error};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_fails_with_unique_violation() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO tweet(id, text, owner_id) VALUES (1, 'Foo', 1)\")\n        .execute(&mut *tx)\n        .await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"INSERT INTO tweet VALUES (1, NOW(), 'Foo', 1);\")\n        .execute(&mut *tx)\n        .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::UniqueViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_foreign_key_violation() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO tweet_reply (tweet_id, text) VALUES (1, 'Reply!');\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::ForeignKeyViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_not_null_violation() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"INSERT INTO tweet (text) VALUES (null);\")\n        .execute(&mut *tx)\n        .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::NotNullViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_check_violation() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO products VALUES (1, 'Product 1', 0);\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::CheckViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_begin_failed() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let res = conn.begin_with(\"SELECT * FROM tweet\").await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::BeginFailed), \"{err:?}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_invalid_save_point_statement() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let mut txn = conn.begin().await?;\n    let txn_conn = sqlx::Acquire::acquire(&mut txn).await?;\n    let res = txn_conn.begin_with(\"BEGIN\").await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::InvalidSavePointStatement), \"{err}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_parameter_count_mismatch_too_few() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"SELECT * FROM tweet WHERE id = ? AND owner_id = ?\")\n            .bind(1_i64)\n            .execute(&mut conn)\n            .await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::Protocol(_)), \"{err}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_parameter_count_mismatch_too_many() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let res: Result<_, sqlx::Error> = sqlx::query(\"SELECT * FROM tweet WHERE id = ?\")\n        .bind(1_i64)\n        .bind(2_i64)\n        .execute(&mut conn)\n        .await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::Protocol(_)), \"{err}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_parameter_count_mismatch_zero_expected() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let res: Result<_, sqlx::Error> = sqlx::query(\"SELECT COUNT(*) FROM tweet\")\n        .bind(1_i64)\n        .execute(&mut conn)\n        .await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::Protocol(_)), \"{err}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mysql/fixtures/comments.sql",
    "content": "insert into comment(comment_id, post_id, user_id, content, created_at)\nvalues (1,\n        1,\n        2,\n        'lol bet ur still bad, 1v1 me',\n        timestamp(now(), '-0:50:00')),\n       (2,\n        1,\n        1,\n        'you''re on!',\n        timestamp(now(), '-0:45:00')),\n       (3,\n        2,\n        1,\n        'lol you''re just mad you lost :P',\n        timestamp(now(), '-0:15:00'));\n"
  },
  {
    "path": "tests/mysql/fixtures/posts.sql",
    "content": "insert into post(post_id, user_id, content, created_at)\nvalues (1,\n        1,\n        'This new computer is lightning-fast!',\n        timestamp(now(), '-1:00:00')),\n       (2,\n        2,\n        '@alice is a haxxor :(',\n        timestamp(now(), '-0:30:00'));\n"
  },
  {
    "path": "tests/mysql/fixtures/users.sql",
    "content": "insert into user(user_id, username)\nvalues (1, 'alice'), (2, 'bob');\n"
  },
  {
    "path": "tests/mysql/macros.rs",
    "content": "use sqlx::{Connection, MySql, MySqlConnection, Transaction};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn macro_select_from_cte() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let account =\n        sqlx::query!(\"select * from (select (1) as id, 'Herp Derpinson' as name, cast(null as char) email) accounts\")\n            .fetch_one(&mut conn)\n            .await?;\n\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, \"Herp Derpinson\");\n    // MySQL can tell us the nullability of expressions, ain't that cool\n    assert_eq!(account.email, None);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn macro_select_from_cte_bind() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let account = sqlx::query!(\n        \"select * from (select (1) as id, 'Herp Derpinson' as name) accounts where id = ?\",\n        1i32\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    println!(\"{account:?}\");\n    println!(\"{}: {}\", account.id, account.name);\n\n    Ok(())\n}\n\n#[derive(Debug)]\nstruct RawAccount {\n    r#type: i32,\n    name: Option<String>,\n}\n\n#[sqlx_macros::test]\nasync fn test_query_as_raw() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let account = sqlx::query_as!(\n        RawAccount,\n        \"SELECT * from (select 1 as type, cast(null as char) as name) accounts\"\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(account.name, None);\n    assert_eq!(account.r#type, 1);\n\n    println!(\"{account:?}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_scalar() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let id = sqlx::query_scalar!(\"select 1\").fetch_one(&mut conn).await?;\n    // MySQL tells us `LONG LONG` while MariaDB just `LONG`\n    assert_eq!(id, 1);\n\n    // invalid column names are ignored\n    let id = sqlx::query_scalar!(r#\"select 1 as `&foo`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(id, 1);\n\n    let id = sqlx::query_scalar!(r#\"select 1 as `foo!`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(id, 1);\n\n    let id = sqlx::query_scalar!(r#\"select 1 as `foo?`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(1));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as `foo: MyInt`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as `foo?: MyInt`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(MyInt(1)));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as `foo!: MyInt`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1));\n\n    let id: MyInt = sqlx::query_scalar!(r#\"select 1 as `foo: _`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1));\n\n    let id: MyInt = sqlx::query_scalar!(r#\"select 1 as `foo?: _`\"#)\n        .fetch_one(&mut conn)\n        .await?\n        // don't hint that it should be `Option<MyInt>`\n        .unwrap();\n\n    assert_eq!(id, MyInt(1));\n\n    let id: MyInt = sqlx::query_scalar!(r#\"select 1 as `foo!: _`\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_as_bool() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    struct Article {\n        id: i32,\n        deleted: bool,\n    }\n\n    let article = sqlx::query_as_unchecked!(\n        Article,\n        \"select * from (select 51 as id, true as deleted) articles\"\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(51, article.id);\n    assert_eq!(true, article.deleted);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_bytes() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let rec = sqlx::query!(\"SELECT X'01AF' as _1\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(rec._1, &[0x01_u8, 0xAF_u8]);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let record = sqlx::query!(\"select * from (select 1 as `id!`) records\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    // MySQL by default tells us `id` is not-null\n    let record = sqlx::query!(\"select * from (select 1 as `id?`) records\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, Some(1));\n\n    Ok(())\n}\n\nasync fn with_test_row<'a>(\n    conn: &'a mut MySqlConnection,\n) -> anyhow::Result<(Transaction<'a, MySql>, MyInt)> {\n    let mut transaction = conn.begin().await?;\n    let id = sqlx::query!(\"INSERT INTO tweet(text, owner_id) VALUES ('#sqlx is pretty cool!', 1)\")\n        .execute(&mut *transaction)\n        .await?\n        .last_insert_id();\n    Ok((transaction, MyInt(id as i64)))\n}\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct MyInt(i64);\n\nstruct Record {\n    id: MyInt,\n}\n\nstruct OptionalRecord {\n    id: Option<MyInt>,\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as!(Record, \"select id as `id: _` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, id);\n\n    // this syntax is also useful for expressions\n    let record = sqlx::query_as!(Record, \"select * from (select 1 as `id: _`) records\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    let record = sqlx::query_as!(OptionalRecord, \"select owner_id as `id: _` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, _) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as!(Record, \"select owner_id as `id!: _` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as!(OptionalRecord, \"select id as `id?: _` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(id));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query!(\"select id as `id: MyInt` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, id);\n\n    // we can also support this syntax for expressions\n    let record = sqlx::query!(\"select * from (select 1 as `id: MyInt`) records\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    let record = sqlx::query!(\"select owner_id as `id: MyInt` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, _) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query!(\"select owner_id as `id!: MyInt` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query!(\"select id as `id?: MyInt` from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(id));\n\n    Ok(())\n}\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(rename_all = \"lowercase\")]\nenum MyEnum {\n    Red,\n    Green,\n    Blue,\n}\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[repr(i32)]\nenum MyCEnum {\n    Red = 0,\n    Green,\n    Blue,\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_enum() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let record = sqlx::query!(\"select * from (select 'red' as `color: MyEnum`) records\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.color, MyEnum::Red);\n\n    let record = sqlx::query!(\"select * from (select 2 as `color: MyCEnum`) records\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.color, MyCEnum::Blue);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_try_from_attr_for_native_type() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(try_from = \"i64\")]\n        id: u64,\n    }\n\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select id from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, id.0 as u64);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_try_from_attr_for_custom_type() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(try_from = \"i64\")]\n        id: Id,\n    }\n\n    #[derive(Debug, PartialEq)]\n    struct Id(i64);\n    impl std::convert::TryFrom<i64> for Id {\n        type Error = std::io::Error;\n        fn try_from(value: i64) -> Result<Self, Self::Error> {\n            Ok(Id(value))\n        }\n    }\n\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select id from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Id(id.0));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_try_from_attr_with_flatten() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(try_from = \"Id\", flatten)]\n        id: u64,\n    }\n\n    #[derive(Debug, PartialEq, sqlx::FromRow)]\n    struct Id {\n        id: i64,\n    }\n\n    impl std::convert::TryFrom<Id> for u64 {\n        type Error = std::io::Error;\n        fn try_from(value: Id) -> Result<Self, Self::Error> {\n            Ok(value.id as u64)\n        }\n    }\n\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select id from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, id.0 as u64);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_try_from_attr_with_complex_type() -> anyhow::Result<()> {\n    mod m {\n        #[derive(sqlx::Type)]\n        #[sqlx(transparent)]\n        pub struct ComplexType<T>(T);\n\n        impl std::convert::TryFrom<ComplexType<i64>> for u64 {\n            type Error = std::num::TryFromIntError;\n            fn try_from(value: ComplexType<i64>) -> Result<Self, Self::Error> {\n                u64::try_from(value.0)\n            }\n        }\n    }\n\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(try_from = \"m::ComplexType<i64>\")]\n        id: u64,\n    }\n\n    let mut conn = new::<MySql>().await?;\n    let (mut conn, id) = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select id from tweet\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, id.0 as u64);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_from_row_json_attr() -> anyhow::Result<()> {\n    #[derive(serde::Deserialize)]\n    struct J {\n        a: u32,\n        b: u32,\n    }\n\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(json)]\n        j: J,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select json_object('a', 1, 'b', 2) as j\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.j.a, 1);\n    assert_eq!(record.j.b, 2);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_from_row_json_attr_nullable() -> anyhow::Result<()> {\n    #[derive(serde::Deserialize)]\n    #[allow(dead_code)]\n    struct J {\n        a: u32,\n        b: u32,\n    }\n\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(json(nullable))]\n        j: Option<J>,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select NULL as j\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert!(record.j.is_none());\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_from_row_json_try_from_attr() -> anyhow::Result<()> {\n    #[derive(serde::Deserialize)]\n    struct J {\n        a: u32,\n        b: u32,\n    }\n\n    // Non-deserializable\n    struct J2 {\n        sum: u32,\n    }\n\n    impl std::convert::From<J> for J2 {\n        fn from(j: J) -> Self {\n            Self { sum: j.a + j.b }\n        }\n    }\n\n    #[derive(sqlx::FromRow)]\n    struct Record {\n        #[sqlx(json, try_from = \"J\")]\n        j: J2,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    let record = sqlx::query_as::<_, Record>(\"select json_object('a', 1, 'b', 2) as j\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.j.sum, 3);\n\n    Ok(())\n}\n\n#[cfg(all(mariadb, not(mariadb = \"10_6\"), feature = \"time\"))]\n#[sqlx_macros::test]\nasync fn test_uuid_is_compatible_mariadb() -> anyhow::Result<()> {\n    use sqlx::types::time::OffsetDateTime;\n    use sqlx::types::Uuid;\n\n    struct Tweet {\n        id: Uuid,\n        text: String,\n        created_at: OffsetDateTime,\n        owner_id: Option<Uuid>,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    sqlx::query!(\"INSERT INTO tweet_with_uuid(text) VALUES ('Hello, world!')\")\n        .execute(&mut conn)\n        .await?;\n\n    let tweets: Vec<Tweet> = sqlx::query_as!(Tweet, \"SELECT * FROM tweet_with_uuid\")\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(tweets.len(), 1);\n\n    assert_eq!(tweets[0].text, \"Hello, world!\");\n\n    Ok(())\n}\n\n// we don't emit bind parameter type-checks for MySQL so testing the overrides is redundant\n"
  },
  {
    "path": "tests/mysql/migrate.rs",
    "content": "use sqlx::migrate::Migrator;\nuse sqlx::mysql::{MySql, MySqlConnection};\nuse sqlx::pool::PoolConnection;\nuse sqlx::Executor;\nuse sqlx::Row;\nuse std::path::Path;\n\n#[sqlx::test(migrations = false)]\nasync fn simple(mut conn: PoolConnection<MySql>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/mysql/migrations_simple\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: String = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_simple_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, \"110_suffix\");\n\n    // running it a 2nd time should still work\n    migrator.run(&mut conn).await?;\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = false)]\nasync fn reversible(mut conn: PoolConnection<MySql>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/mysql/migrations_reversible\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 101);\n\n    // roll back nothing (last version)\n    migrator.undo(&mut conn, 20220721125033).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 101);\n\n    // roll back one version\n    migrator.undo(&mut conn, 20220721124650).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 100);\n\n    Ok(())\n}\n\n/// Ensure that we have a clean initial state.\nasync fn clean_up(conn: &mut MySqlConnection) -> anyhow::Result<()> {\n    conn.execute(\"DROP TABLE migrations_simple_test\").await.ok();\n    conn.execute(\"DROP TABLE migrations_reversible_test\")\n        .await\n        .ok();\n    conn.execute(\"DROP TABLE _sqlx_migrations\").await.ok();\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mysql/migrations/1_user.sql",
    "content": "create table user\n(\n    -- integer primary keys are the most efficient in SQLite\n    user_id  integer primary key auto_increment,\n    -- indexed text values have to have a max length\n    username varchar(16) unique not null\n);\n"
  },
  {
    "path": "tests/mysql/migrations/2_post.sql",
    "content": "create table post\n(\n    post_id    integer primary key auto_increment,\n    user_id    integer not null references user (user_id),\n    content    text    not null,\n    -- Defaults have to be wrapped in parenthesis\n    created_at datetime default current_timestamp\n);\n\ncreate index post_created_at on post (created_at desc);\n"
  },
  {
    "path": "tests/mysql/migrations/3_comment.sql",
    "content": "create table comment\n(\n    comment_id integer primary key,\n    post_id    integer not null references post (post_id),\n    user_id    integer not null references user (user_id),\n    content    text    not null,\n    created_at datetime default current_timestamp\n);\n\ncreate index comment_created_at on comment (created_at desc);\n"
  },
  {
    "path": "tests/mysql/migrations_reversible/20220721124650_add_table.down.sql",
    "content": "DROP TABLE migrations_reversible_test;\n"
  },
  {
    "path": "tests/mysql/migrations_reversible/20220721124650_add_table.up.sql",
    "content": "CREATE TABLE migrations_reversible_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_reversible_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/mysql/migrations_reversible/20220721125033_modify_column.down.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload - 1;\n"
  },
  {
    "path": "tests/mysql/migrations_reversible/20220721125033_modify_column.up.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload + 1;\n"
  },
  {
    "path": "tests/mysql/migrations_simple/20220721115250_add_test_table.sql",
    "content": "CREATE TABLE migrations_simple_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_simple_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/mysql/migrations_simple/20220721115524_convert_type.sql",
    "content": "-- Perform a tricky conversion of the payload.\n--\n-- This script will only succeed once and will fail if executed twice.\n\n-- set up temporary target column\nALTER TABLE migrations_simple_test\nADD some_payload_tmp TEXT;\n\n-- perform conversion\n-- This will fail if `some_payload` is already a string column due to the addition.\n-- We add a suffix after the addition to ensure that the SQL database does not silently cast the string back to an \n-- integer.\nUPDATE migrations_simple_test\nSET some_payload_tmp = CONCAT(CAST((some_payload + 10) AS CHAR(3)), '_suffix');\n\n-- remove original column including the content\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload;\n\n-- prepare new payload column (nullable, so we can copy over the data)\nALTER TABLE migrations_simple_test\nADD some_payload TEXT;\n\n-- copy new values\nUPDATE migrations_simple_test\nSET some_payload = some_payload_tmp;\n\n-- \"freeze\" column\nALTER TABLE migrations_simple_test\nMODIFY some_payload TEXT NOT NULL;\n\n-- clean up\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload_tmp;\n"
  },
  {
    "path": "tests/mysql/my.cnf",
    "content": "[mysqld]\nssl-ca=/etc/mysql/ssl/ca.crt\nssl-cert=/etc/mysql/ssl/server.crt\nssl-key=/etc/mysql/ssl/server.key\n"
  },
  {
    "path": "tests/mysql/mysql.rs",
    "content": "use anyhow::Context;\nuse futures_util::TryStreamExt;\nuse sqlx::mysql::{MySql, MySqlConnection, MySqlPool, MySqlPoolOptions, MySqlRow};\nuse sqlx::{Column, Connection, Executor, Row, SqlSafeStr, Statement, TypeInfo};\nuse sqlx_core::connection::ConnectOptions;\nuse sqlx_mysql::MySqlConnectOptions;\nuse sqlx_test::{new, setup_if_needed};\nuse std::env;\nuse url::Url;\n\n#[sqlx_macros::test]\nasync fn it_connects() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    conn.ping().await?;\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_connects_without_password() -> anyhow::Result<()> {\n    setup_if_needed();\n\n    let mut url = Url::parse(&env::var(\"DATABASE_URL\").context(\"expected DATABASE_URL\")?)\n        .context(\"error parsing DATABASE_URL\")?;\n\n    url.set_username(\"no_password\").unwrap();\n    url.set_password(None).unwrap();\n\n    let mut conn = MySqlConnectOptions::from_url(&url)?.connect().await?;\n\n    let vars = sqlx::raw_sql(\"SHOW VARIABLES\").fetch_all(&mut conn).await?;\n\n    assert!(!vars.is_empty());\n\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_maths() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let value = sqlx::query(\"select 1 + CAST(? AS SIGNED)\")\n        .bind(5_i32)\n        .try_map(|row: MySqlRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(6i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fail_at_querying() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let _ = conn.execute(sqlx::query(\"SELECT 1\")).await?;\n\n    // we are testing that this does not cause a panic!\n    let _ = conn\n        .execute(sqlx::query(\"SELECT non_existence_table\"))\n        .await;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY);\n            \"#,\n        )\n        .await?;\n\n    for index in 1..=10_i32 {\n        let done = sqlx::query(\"INSERT INTO users (id) VALUES (?)\")\n            .bind(index)\n            .execute(&mut conn)\n            .await?;\n\n        assert_eq!(done.rows_affected(), 1);\n    }\n\n    let sum: i32 = sqlx::query(\"SELECT id FROM users\")\n        .try_map(|row: MySqlRow| row.try_get::<i32, _>(0))\n        .fetch(&mut conn)\n        .try_fold(0_i32, |acc, x| async move { Ok(acc + x) })\n        .await?;\n\n    assert_eq!(sum, 55);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes_with_pool() -> anyhow::Result<()> {\n    let pool: MySqlPool = MySqlPoolOptions::new()\n        .min_connections(2)\n        .max_connections(2)\n        .test_before_acquire(false)\n        .connect(&dotenvy::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let rows = pool.fetch_all(\"SELECT 1; SELECT 2\").await?;\n\n    assert_eq!(rows.len(), 2);\n\n    let count = pool\n        .fetch(\"SELECT 1; SELECT 2\")\n        .try_fold(0, |acc, _| async move { Ok(acc + 1) })\n        .await?;\n\n    assert_eq!(count, 2);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_works_with_cache_disabled() -> anyhow::Result<()> {\n    setup_if_needed();\n\n    let mut url = url::Url::parse(&env::var(\"DATABASE_URL\")?)?;\n    url.query_pairs_mut()\n        .append_pair(\"statement-cache-capacity\", \"0\");\n\n    let mut conn = MySqlConnection::connect(url.as_ref()).await?;\n\n    for index in 1..=10_i32 {\n        let _ = sqlx::query(\"SELECT ?\")\n            .bind(index)\n            .execute(&mut conn)\n            .await?;\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_drops_results_in_affected_rows() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    // ~1800 rows should be iterated and dropped\n    let done = conn\n        .execute(\"select * from mysql.time_zone limit 1575\")\n        .await?;\n\n    // In MySQL, rows being returned isn't enough to flag it as an _affected_ row\n    assert_eq!(0, done.rows_affected());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_selects_null() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let (val,): (Option<i32>,) = sqlx::query_as(\"SELECT NULL\").fetch_one(&mut conn).await?;\n\n    assert!(val.is_none());\n\n    let val: Option<i32> = conn.fetch_one(\"SELECT NULL\").await?.try_get(0)?;\n\n    assert!(val.is_none());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fetch_one_and_ping() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let (_id,): (i32,) = sqlx::query_as(\"SELECT 1 as id\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    conn.ping().await?;\n\n    let (_id,): (i32,) = sqlx::query_as(\"SELECT 1 as id\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    Ok(())\n}\n\n/// Test that we can interleave reads and writes to the database in one simple query.\n#[sqlx_macros::test]\nasync fn it_interleaves_reads_and_writes() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let mut s = conn.fetch(\n        \"\nCREATE TEMPORARY TABLE messages (\n    id BIGINT PRIMARY KEY AUTO_INCREMENT,\n    text TEXT NOT NULL\n);\n\nSELECT 'Hello World' as _1;\n\nINSERT INTO messages (text) VALUES ('this is a test');\n\nSELECT id, text FROM messages;\n        \",\n    );\n\n    let row = s.try_next().await?.unwrap();\n\n    assert!(\"Hello World\" == row.try_get::<&str, _>(\"_1\")?);\n\n    let row = s.try_next().await?.unwrap();\n\n    let id: i64 = row.try_get(\"id\")?;\n    let text: &str = row.try_get(\"text\")?;\n\n    assert_eq!(1_i64, id);\n    assert_eq!(\"this is a test\", text);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_caches_statements() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT ? AS val\")\n            .bind(i)\n            .persistent(true)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: u32 = row.get(\"val\");\n\n        assert_eq!(i, val);\n    }\n\n    assert_eq!(1, conn.cached_statements_size());\n    conn.clear_cached_statements().await?;\n    assert_eq!(0, conn.cached_statements_size());\n\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT ? AS val\")\n            .bind(i)\n            .persistent(false)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: u32 = row.get(\"val\");\n\n        assert_eq!(i, val);\n    }\n\n    assert_eq!(0, conn.cached_statements_size());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_closes_statements_with_persistent_disabled() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let old_statement_count = select_statement_count(&mut conn).await.unwrap_or_default();\n\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT ? AS val\")\n            .bind(i)\n            .persistent(false)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: i32 = row.get(\"val\");\n\n        assert_eq!(i, val);\n    }\n\n    let new_statement_count = select_statement_count(&mut conn).await.unwrap_or_default();\n\n    assert_eq!(old_statement_count, new_statement_count);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_closes_statements_with_cache_disabled() -> anyhow::Result<()> {\n    setup_if_needed();\n\n    let mut url = url::Url::parse(&env::var(\"DATABASE_URL\")?)?;\n    url.query_pairs_mut()\n        .append_pair(\"statement-cache-capacity\", \"0\");\n\n    let mut conn = MySqlConnection::connect(url.as_ref()).await?;\n\n    let old_statement_count = select_statement_count(&mut conn).await.unwrap_or_default();\n\n    for index in 1..=10_i32 {\n        let _ = sqlx::query(\"SELECT ?\")\n            .bind(index)\n            .execute(&mut conn)\n            .await?;\n    }\n\n    let new_statement_count = select_statement_count(&mut conn).await.unwrap_or_default();\n\n    assert_eq!(old_statement_count, new_statement_count);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_bind_null_and_non_null_issue_540() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let row = sqlx::query(\"SELECT ?, ?\")\n        .bind(50_i32)\n        .bind(None::<i32>)\n        .fetch_one(&mut conn)\n        .await?;\n\n    let v0: Option<i32> = row.get(0);\n    let v1: Option<i32> = row.get(1);\n\n    assert_eq!(v0, Some(50));\n    assert_eq!(v1, None);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_bind_only_null_issue_540() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    let row = sqlx::query(\"SELECT ?\")\n        .bind(None::<i32>)\n        .fetch_one(&mut conn)\n        .await?;\n\n    let v0: Option<i32> = row.get(0);\n\n    assert_eq!(v0, None);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_bind_and_return_years() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    sqlx::raw_sql(\n        r#\"\nCREATE TEMPORARY TABLE too_many_years (\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    the YEAR NOT NULL\n);\n    \"#,\n    )\n    .execute(&mut conn)\n    .await?;\n\n    sqlx::query(\n        r#\"\nINSERT INTO too_many_years ( the ) VALUES ( ? );\n    \"#,\n    )\n    .bind(2142)\n    .execute(&mut conn)\n    .await?;\n\n    let the: u16 = sqlx::query_scalar(\"SELECT the FROM too_many_years\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(the, 2142);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_prepare_then_execute() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    let mut tx = conn.begin().await?;\n\n    let tweet_id: u64 = sqlx::query(\"INSERT INTO tweet ( text ) VALUES ( 'Hello, World' )\")\n        .execute(&mut *tx)\n        .await?\n        .last_insert_id();\n\n    let statement = tx\n        .prepare(\"SELECT * FROM tweet WHERE id = ?\".into_sql_str())\n        .await?;\n\n    assert_eq!(statement.column(0).name(), \"id\");\n    assert_eq!(statement.column(1).name(), \"created_at\");\n    assert_eq!(statement.column(2).name(), \"text\");\n    assert_eq!(statement.column(3).name(), \"owner_id\");\n\n    assert_eq!(statement.column(0).type_info().name(), \"BIGINT\");\n    assert_eq!(statement.column(1).type_info().name(), \"TIMESTAMP\");\n    assert_eq!(statement.column(2).type_info().name(), \"TEXT\");\n    assert_eq!(statement.column(3).type_info().name(), \"BIGINT\");\n\n    let row = statement.query().bind(tweet_id).fetch_one(&mut *tx).await?;\n    let tweet_text: &str = row.try_get(\"text\")?;\n\n    assert_eq!(tweet_text, \"Hello, World\");\n\n    Ok(())\n}\n\n// repro is more reliable with the basic scheduler used by `#[tokio::test]`\n#[cfg(feature = \"_rt-tokio\")]\n#[tokio::test]\nasync fn test_issue_622() -> anyhow::Result<()> {\n    use std::time::Instant;\n\n    setup_if_needed();\n\n    let pool = MySqlPoolOptions::new()\n        .max_connections(1) // also fails with higher counts, e.g. 5\n        .connect(&std::env::var(\"DATABASE_URL\").unwrap())\n        .await?;\n\n    println!(\"pool state: {pool:?}\");\n\n    let mut handles = vec![];\n\n    // given repro spawned 100 tasks but I found it reliably reproduced with 3\n    for i in 0..3 {\n        let pool = pool.clone();\n\n        handles.push(sqlx_core::rt::spawn(async move {\n            {\n                let mut conn = pool.acquire().await.unwrap();\n\n                let _ = sqlx::query(\"SELECT 1\").fetch_one(&mut *conn).await.unwrap();\n\n                // conn gets dropped here and should be returned to the pool\n            }\n\n            // (do some other work here without holding on to a connection)\n            // this actually fixes the issue, depending on the timeout used\n            // sqlx_core::rt::sleep(Duration::from_millis(500)).await;\n\n            {\n                let start = Instant::now();\n                match pool.acquire().await {\n                    Ok(conn) => {\n                        println!(\"{} acquire took {:?}\", i, start.elapsed());\n                        drop(conn);\n                    }\n                    Err(e) => panic!(\"{i} acquire returned error: {e} pool state: {pool:?}\"),\n                }\n            }\n\n            Result::<(), anyhow::Error>::Ok(())\n        }));\n    }\n\n    futures_util::future::try_join_all(handles).await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_work_with_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n    sqlx::raw_sql(\"CREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY);\")\n        .execute(&mut conn)\n        .await?;\n\n    // begin .. rollback\n\n    let mut tx = conn.begin().await?;\n    sqlx::query(\"INSERT INTO users (id) VALUES (?)\")\n        .bind(1_i32)\n        .execute(&mut *tx)\n        .await?;\n    let count: i64 = sqlx::query_scalar(\"SELECT COUNT(*) FROM users\")\n        .fetch_one(&mut *tx)\n        .await?;\n    assert_eq!(count, 1);\n    tx.rollback().await?;\n    let count: i64 = sqlx::query_scalar(\"SELECT COUNT(*) FROM users\")\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(count, 0);\n\n    // begin .. commit\n\n    let mut tx = conn.begin().await?;\n    sqlx::query(\"INSERT INTO users (id) VALUES (?)\")\n        .bind(1_i32)\n        .execute(&mut *tx)\n        .await?;\n    tx.commit().await?;\n    let count: i64 = sqlx::query_scalar(\"SELECT COUNT(*) FROM users\")\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(count, 1);\n\n    // begin .. (drop)\n\n    {\n        let mut tx = conn.begin().await?;\n\n        sqlx::query(\"INSERT INTO users (id) VALUES (?)\")\n            .bind(2)\n            .execute(&mut *tx)\n            .await?;\n        let count: i64 = sqlx::query_scalar(\"SELECT COUNT(*) FROM users\")\n            .fetch_one(&mut *tx)\n            .await?;\n        assert_eq!(count, 2);\n        // tx is dropped\n    }\n    let count: i64 = sqlx::query_scalar(\"SELECT COUNT(*) FROM users\")\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(count, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_handle_split_packets() -> anyhow::Result<()> {\n    // This will only take effect on new connections\n    new::<MySql>()\n        .await?\n        .execute(\"SET GLOBAL max_allowed_packet = 4294967297\")\n        .await?;\n\n    let mut conn = new::<MySql>().await?;\n\n    conn.execute(\n        r#\"\nCREATE TEMPORARY TABLE large_table (data LONGBLOB);\n        \"#,\n    )\n    .await?;\n\n    let data = vec![0x41; 0xFF_FF_FF * 2];\n\n    sqlx::query(\"INSERT INTO large_table (data) VALUES (?)\")\n        .bind(&data)\n        .execute(&mut conn)\n        .await?;\n\n    let ret: Vec<u8> = sqlx::query_scalar(\"SELECT * FROM large_table\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(ret, data);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_shrink_buffers() -> anyhow::Result<()> {\n    // We don't really have a good way to test that `.shrink_buffers()` functions as expected\n    // without exposing a lot of internals, but we can at least be sure it doesn't\n    // materially affect the operation of the connection.\n\n    let mut conn = new::<MySql>().await?;\n\n    // The connection buffer is only 8 KiB by default so this should definitely force it to grow.\n    let data = \"This string should be 32 bytes!\\n\".repeat(1024);\n    assert_eq!(data.len(), 32 * 1024);\n\n    let ret: String = sqlx::query_scalar(\"SELECT ?\")\n        .bind(&data)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(ret, data);\n\n    conn.shrink_buffers();\n\n    let ret: i64 = sqlx::query_scalar(\"SELECT ?\")\n        .bind(12345678i64)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(ret, 12345678i64);\n\n    Ok(())\n}\n\nasync fn select_statement_count(conn: &mut MySqlConnection) -> Result<i64, sqlx::Error> {\n    // Fails if performance schema does not exist\n    sqlx::query_scalar(\n        r#\"\n        SELECT COUNT(*)\n        FROM performance_schema.threads AS t\n        INNER JOIN performance_schema.prepared_statements_instances AS psi\n            ON psi.OWNER_THREAD_ID = t.THREAD_ID \n        WHERE t.processlist_id = CONNECTION_ID()\n        \"#,\n    )\n    .fetch_one(conn)\n    .await\n}\n\n#[sqlx_macros::test]\nasync fn issue_3200() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    sqlx::raw_sql(\n        \"\\\n        CREATE TABLE IF NOT EXISTS users\n        (\n            `id`                     BIGINT AUTO_INCREMENT,\n            `username`               VARCHAR(128) NOT NULL,\n            PRIMARY KEY (id)\n        );\n    \",\n    )\n    .execute(&mut conn)\n    .await?;\n\n    let result = sqlx::raw_sql(\n        \"\\\n        SET @myvar := 'test@test.com';\n        select id from users where username = @myvar;\n    \",\n    )\n    .fetch_optional(&mut conn)\n    .await?;\n\n    assert!(result.is_none(), \"{result:?}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mysql/rustsec.rs",
    "content": "use sqlx::{Error, MySql};\nuse std::io;\n\nuse sqlx_test::new;\n\n// https://rustsec.org/advisories/RUSTSEC-2024-0363.html\n//\n// During the audit the MySQL driver was found to be *unlikely* to be vulnerable to the exploit,\n// so this just serves as a sanity check.\n#[sqlx::test]\nasync fn rustsec_2024_0363() -> anyhow::Result<()> {\n    let overflow_len = 4 * 1024 * 1024 * 1024; // 4 GiB\n\n    let padding = \" \".repeat(overflow_len);\n\n    let payload = \"UPDATE injection_target SET message = 'you''ve been pwned!' WHERE id = 1\";\n\n    let mut injected_value = String::with_capacity(overflow_len + payload.len());\n\n    injected_value.push_str(&padding);\n    injected_value.push_str(payload);\n\n    // Since this is so large, keeping it around until the end *can* lead to getting OOM-killed.\n    drop(padding);\n\n    let mut conn = new::<MySql>().await?;\n\n    sqlx::raw_sql(\n        \"CREATE TEMPORARY TABLE injection_target(id INTEGER PRIMARY KEY AUTO_INCREMENT, message TEXT);\\n\\\n         INSERT INTO injection_target(message) VALUES ('existing message');\",\n    )\n    .execute(&mut conn)\n    .await?;\n\n    // We can't concatenate a query string together like the other tests\n    // because it would just demonstrate a regular old SQL injection.\n    let res = sqlx::query(\"INSERT INTO injection_target(message) VALUES (?)\")\n        .bind(&injected_value)\n        .execute(&mut conn)\n        .await;\n\n    if let Err(e) = res {\n        // Connection rejected the query; we're happy.\n        //\n        // Current observed behavior is that `mysqld` closes the connection before we're even done\n        // sending the message, giving us a \"Broken pipe\" error.\n        //\n        // As it turns out, MySQL has a tight limit on packet sizes (even after splitting)\n        // by default: https://dev.mysql.com/doc/refman/8.4/en/packet-too-large.html\n        if matches!(e, Error::Io(ref ioe) if ioe.kind() == io::ErrorKind::BrokenPipe) {\n            return Ok(());\n        }\n\n        panic!(\"unexpected error: {e:?}\");\n    }\n\n    let messages: Vec<String> =\n        sqlx::query_scalar(\"SELECT message FROM injection_target ORDER BY id\")\n            .fetch_all(&mut conn)\n            .await?;\n\n    assert_eq!(messages[0], \"existing_message\");\n    assert_eq!(messages[1].len(), injected_value.len());\n\n    // Injection didn't affect our database; we're happy.\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mysql/setup-mariadb.sql",
    "content": "-- additional SQL to execute for MariaDB databases\n\nCREATE TABLE tweet_with_uuid\n(\n    -- UUID is only a bespoke datatype in MariaDB.\n    id         UUID PRIMARY KEY   DEFAULT UUID(),\n    created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n    text       TEXT      NOT NULL,\n    owner_id   UUID\n);\n"
  },
  {
    "path": "tests/mysql/setup.sql",
    "content": "-- https://github.com/prisma/database-schema-examples/tree/master/postgres/basic-twitter#basic-twitter\nCREATE TABLE tweet\n(\n    id         BIGINT PRIMARY KEY AUTO_INCREMENT,\n    created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n    text       TEXT      NOT NULL,\n    owner_id   BIGINT\n);\n\nCREATE TABLE tweet_reply\n(\n    id         BIGINT PRIMARY KEY AUTO_INCREMENT,\n    tweet_id   BIGINT    NOT NULL,\n    created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n    text       TEXT      NOT NULL,\n    owner_id   BIGINT,\n    CONSTRAINT tweet_id_fk FOREIGN KEY (tweet_id) REFERENCES tweet(id)\n);\n\nCREATE TABLE products (\n    product_no INTEGER,\n    name TEXT,\n    price NUMERIC CHECK (price > 0)\n);\n\n-- Create a user without a password to test passwordless auth.\nCREATE USER 'no_password'@'%';\n\n-- The minimum privilege apparently needed to connect to a specific database.\n-- Granting no privileges, or just `GRANT USAGE`, gives an \"access denied\" error.\n-- https://github.com/launchbadge/sqlx/issues/3484#issuecomment-2350901546\nGRANT SELECT ON sqlx.* TO 'no_password'@'%';\n"
  },
  {
    "path": "tests/mysql/test-attr.rs",
    "content": "// The no-arg variant is covered by other tests already.\n\nuse sqlx::MySqlPool;\n\nconst MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!(\"tests/mysql/migrations\");\n\n#[sqlx::test]\nasync fn it_gets_a_pool(pool: MySqlPool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n\n    let db_name: String = sqlx::query_scalar(\"select database()\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert!(db_name.starts_with(\"_sqlx_test_\"), \"db_name: {:?}\", db_name);\n\n    Ok(())\n}\n\n// This should apply migrations and then `fixtures/users.sql`\n#[sqlx::test(migrations = \"tests/mysql/migrations\", fixtures(\"users\"))]\nasync fn it_gets_users(pool: MySqlPool) -> sqlx::Result<()> {\n    let usernames: Vec<String> =\n        sqlx::query_scalar(r#\"SELECT username FROM user ORDER BY username\"#)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(usernames, [\"alice\", \"bob\"]);\n\n    let post_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM post)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!post_exists);\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = \"tests/mysql/migrations\", fixtures(\"users\", \"posts\"))]\nasync fn it_gets_posts(pool: MySqlPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n#[sqlx::test(\n    migrations = \"tests/mysql/migrations\",\n    fixtures(\"../fixtures/mysql/users.sql\", \"../fixtures/mysql/posts.sql\")\n)]\nasync fn it_gets_posts_explicit_fixtures_path(pool: MySqlPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n#[sqlx::test(\n    migrations = \"tests/mysql/migrations\",\n    fixtures(\"../fixtures/mysql/users.sql\"),\n    fixtures(\"posts\")\n)]\nasync fn it_gets_posts_mixed_fixtures_path(pool: MySqlPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n#[sqlx::test(\n    migrations = \"tests/mysql/migrations\",\n    fixtures(path = \"../fixtures/mysql\", scripts(\"users\", \"posts\"))\n)]\nasync fn it_gets_posts_custom_relative_fixtures_path(pool: MySqlPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// Try `migrator`\n#[sqlx::test(migrator = \"MIGRATOR\", fixtures(\"users\", \"posts\", \"comments\"))]\nasync fn it_gets_comments(pool: MySqlPool) -> sqlx::Result<()> {\n    let post_1_comments: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM comment WHERE post_id = ? ORDER BY created_at\")\n            .bind(&1)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_1_comments,\n        [\"lol bet ur still bad, 1v1 me\", \"you're on!\"]\n    );\n\n    let post_2_comments: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM comment WHERE post_id = ? ORDER BY created_at\")\n            .bind(&2)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(post_2_comments, [\"lol you're just mad you lost :P\"]);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/mysql/types.rs",
    "content": "extern crate time_ as time;\n\nuse std::borrow::Cow;\nuse std::net::SocketAddr;\nuse std::rc::Rc;\n#[cfg(feature = \"rust_decimal\")]\nuse std::str::FromStr;\nuse std::sync::Arc;\n\nuse sqlx::mysql::MySql;\nuse sqlx::{Executor, Row};\n\nuse sqlx::types::Text;\n\nuse sqlx::mysql::types::MySqlTime;\nuse sqlx_mysql::types::MySqlTimeSign;\n\nuse sqlx_test::{new, test_prepared_type, test_type};\n\ntest_type!(bool(MySql, \"false\" == false, \"true\" == true));\n\ntest_type!(u8(MySql, \"CAST(253 AS UNSIGNED)\" == 253_u8));\ntest_type!(i8(MySql, \"5\" == 5_i8, \"0\" == 0_i8));\n\ntest_type!(u16(MySql, \"CAST(21415 AS UNSIGNED)\" == 21415_u16));\ntest_type!(i16(MySql, \"21415\" == 21415_i16));\n\ntest_type!(u32(MySql, \"CAST(2141512 AS UNSIGNED)\" == 2141512_u32));\ntest_type!(i32(MySql, \"2141512\" == 2141512_i32));\n\ntest_type!(u64(MySql, \"CAST(2141512 AS UNSIGNED)\" == 2141512_u64));\ntest_type!(i64(MySql, \"2141512\" == 2141512_i64));\n\ntest_type!(f64(MySql, \"3.14159265e0\" == 3.14159265_f64));\n\n// NOTE: This behavior can be very surprising. MySQL implicitly widens FLOAT bind parameters\n//       to DOUBLE. This results in the weirdness you see below. MySQL generally recommends to stay\n//       away from FLOATs.\ntest_type!(f32(MySql, \"3.1410000324249268e0\" == 3.141f32 as f64 as f32));\n\ntest_type!(string<String>(MySql,\n    \"'helloworld'\" == \"helloworld\",\n    \"''\" == \"\"\n));\n\ntest_type!(bytes<Vec<u8>>(MySql,\n    \"X'DEADBEEF'\"\n        == vec![0xDE_u8, 0xAD, 0xBE, 0xEF],\n    \"X''\"\n        == Vec::<u8>::new(),\n    \"X'0000000052'\"\n        == vec![0_u8, 0, 0, 0, 0x52]\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid<sqlx::types::Uuid>(MySql,\n    \"x'b731678f636f4135bc6f19440c13bd19'\"\n        == sqlx::types::Uuid::parse_str(\"b731678f-636f-4135-bc6f-19440c13bd19\").unwrap(),\n    \"x'00000000000000000000000000000000'\"\n        == sqlx::types::Uuid::parse_str(\"00000000-0000-0000-0000-000000000000\").unwrap()\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid_hyphenated<sqlx::types::uuid::fmt::Hyphenated>(MySql,\n    \"'b731678f-636f-4135-bc6f-19440c13bd19'\"\n        == sqlx::types::Uuid::parse_str(\"b731678f-636f-4135-bc6f-19440c13bd19\").unwrap().hyphenated(),\n    \"'00000000-0000-0000-0000-000000000000'\"\n        == sqlx::types::Uuid::parse_str(\"00000000-0000-0000-0000-000000000000\").unwrap().hyphenated()\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid_simple<sqlx::types::uuid::fmt::Simple>(MySql,\n    \"'b731678f636f4135bc6f19440c13bd19'\"\n        == sqlx::types::Uuid::parse_str(\"b731678f636f4135bc6f19440c13bd19\").unwrap().simple(),\n    \"'00000000000000000000000000000000'\"\n        == sqlx::types::Uuid::parse_str(\"00000000000000000000000000000000\").unwrap().simple()\n));\n\ntest_type!(mysql_time<MySqlTime>(MySql,\n    \"TIME '00:00:00.000000'\" == MySqlTime::ZERO,\n    \"TIME '-00:00:00.000000'\" == MySqlTime::ZERO,\n    \"TIME '838:59:59.0'\" == MySqlTime::MAX,\n    \"TIME '-838:59:59.0'\" == MySqlTime::MIN,\n    \"TIME '123:45:56.890'\" == MySqlTime::new(MySqlTimeSign::Positive, 123, 45, 56, 890_000).unwrap(),\n    \"TIME '-123:45:56.890'\" == MySqlTime::new(MySqlTimeSign::Negative, 123, 45, 56, 890_000).unwrap(),\n    \"TIME '123:45:56.890011'\" == MySqlTime::new(MySqlTimeSign::Positive, 123, 45, 56, 890_011).unwrap(),\n    \"TIME '-123:45:56.890011'\" == MySqlTime::new(MySqlTimeSign::Negative, 123, 45, 56, 890_011).unwrap(),\n));\n\n#[cfg(feature = \"chrono\")]\nmod chrono {\n    use sqlx::types::chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc};\n\n    use super::*;\n\n    test_type!(chrono_date<NaiveDate>(MySql,\n        \"DATE '2001-01-05'\" == NaiveDate::from_ymd_opt(2001, 1, 5).unwrap(),\n        \"DATE '2050-11-23'\" == NaiveDate::from_ymd_opt(2050, 11, 23).unwrap()\n    ));\n\n    test_type!(chrono_time_zero<NaiveTime>(MySql,\n        \"TIME '00:00:00.000000'\" == NaiveTime::from_hms_micro_opt(0, 0, 0, 0).unwrap()\n    ));\n\n    test_type!(chrono_time<NaiveTime>(MySql,\n        \"TIME '05:10:20.115100'\" == NaiveTime::from_hms_micro_opt(5, 10, 20, 115100).unwrap()\n    ));\n\n    test_type!(chrono_date_time<NaiveDateTime>(MySql,\n        \"TIMESTAMP '2019-01-02 05:10:20'\" == NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_opt(5, 10, 20).unwrap()\n    ));\n\n    test_type!(chrono_timestamp<DateTime::<Utc>>(MySql,\n        \"TIMESTAMP '2019-01-02 05:10:20.115100'\"\n            == Utc.from_utc_datetime(\n                &NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_micro_opt(5, 10, 20, 115100).unwrap(),\n            )\n    ));\n\n    #[sqlx_macros::test]\n    async fn test_type_chrono_zero_date() -> anyhow::Result<()> {\n        let mut conn = sqlx_test::new::<MySql>().await?;\n\n        // ensure that zero dates are turned on\n        // newer MySQL has these disabled by default\n\n        conn.execute(\"SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_IN_DATE', '');\")\n            .await?;\n\n        conn.execute(\"SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_DATE', '');\")\n            .await?;\n\n        // date\n\n        let row = sqlx::query(\"SELECT DATE '0000-00-00'\")\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: Option<NaiveDate> = row.get(0);\n\n        assert_eq!(val, None);\n        assert!(row.try_get::<NaiveDate, _>(0).is_err());\n\n        // datetime\n\n        let row = sqlx::query(\"SELECT TIMESTAMP '0000-00-00 00:00:00'\")\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: Option<NaiveDateTime> = row.get(0);\n\n        assert_eq!(val, None);\n        assert!(row.try_get::<NaiveDateTime, _>(0).is_err());\n\n        Ok(())\n    }\n}\n\n#[cfg(feature = \"time\")]\nmod time_tests {\n    use time::macros::{date, time};\n\n    use sqlx::types::time::{Date, OffsetDateTime, PrimitiveDateTime, Time};\n\n    use super::*;\n\n    test_type!(time_date<Date>(\n        MySql,\n        \"DATE '2001-01-05'\" == date!(2001 - 1 - 5),\n        \"DATE '2050-11-23'\" == date!(2050 - 11 - 23)\n    ));\n\n    test_type!(time_time_zero<Time>(\n        MySql,\n        \"TIME '00:00:00.000000'\" == time!(00:00:00.000000)\n    ));\n\n    test_type!(time_time<Time>(\n        MySql,\n        \"TIME '05:10:20.115100'\" == time!(5:10:20.115100)\n    ));\n\n    test_type!(time_date_time<PrimitiveDateTime>(\n        MySql,\n        \"TIMESTAMP '2019-01-02 05:10:20'\" == date!(2019 - 1 - 2).with_time(time!(5:10:20)),\n        \"TIMESTAMP '2019-01-02 05:10:20.115100'\"\n            == date!(2019 - 1 - 2).with_time(time!(5:10:20.115100))\n    ));\n\n    test_type!(time_timestamp<OffsetDateTime>(\n        MySql,\n        \"TIMESTAMP '2019-01-02 05:10:20.115100'\"\n            == date!(2019 - 1 - 2)\n                .with_time(time!(5:10:20.115100))\n                .assume_utc()\n    ));\n\n    #[sqlx_macros::test]\n    async fn test_type_time_zero_date() -> anyhow::Result<()> {\n        let mut conn = sqlx_test::new::<MySql>().await?;\n\n        // ensure that zero dates are turned on\n        // newer MySQL has these disabled by default\n\n        conn.execute(\"SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_IN_DATE', '');\")\n            .await?;\n\n        conn.execute(\"SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_DATE', '');\")\n            .await?;\n\n        // date\n\n        let row = sqlx::query(\"SELECT DATE '0000-00-00'\")\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: Option<Date> = row.get(0);\n\n        assert_eq!(val, None);\n        assert!(row.try_get::<Date, _>(0).is_err());\n\n        // datetime\n\n        let row = sqlx::query(\"SELECT TIMESTAMP '0000-00-00 00:00:00'\")\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: Option<PrimitiveDateTime> = row.get(0);\n\n        assert_eq!(val, None);\n        assert!(row.try_get::<PrimitiveDateTime, _>(0).is_err());\n\n        Ok(())\n    }\n}\n\n#[cfg(feature = \"bigdecimal\")]\ntest_type!(bigdecimal<sqlx::types::BigDecimal>(\n    MySql,\n    \"CAST(0 as DECIMAL(0, 0))\" == \"0\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"CAST(1 AS DECIMAL(1, 0))\" == \"1\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"CAST(10000 AS DECIMAL(5, 0))\" == \"10000\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"CAST(0.1 AS DECIMAL(2, 1))\" == \"0.1\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"CAST(0.01234 AS DECIMAL(6, 5))\" == \"0.01234\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"CAST(12.34 AS DECIMAL(4, 2))\" == \"12.34\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"CAST(12345.6789 AS DECIMAL(9, 4))\" == \"12345.6789\".parse::<sqlx::types::BigDecimal>().unwrap(),\n));\n\n#[cfg(feature = \"rust_decimal\")]\ntest_type!(decimal<sqlx::types::Decimal>(MySql,\n    \"CAST(0 as DECIMAL(0, 0))\" == sqlx::types::Decimal::from_str(\"0\").unwrap(),\n    \"CAST(1 AS DECIMAL(1, 0))\" == sqlx::types::Decimal::from_str(\"1\").unwrap(),\n    \"CAST(10000 AS DECIMAL(5, 0))\" == sqlx::types::Decimal::from_str(\"10000\").unwrap(),\n    \"CAST(0.1 AS DECIMAL(2, 1))\" == sqlx::types::Decimal::from_str(\"0.1\").unwrap(),\n    \"CAST(0.01234 AS DECIMAL(6, 5))\" == sqlx::types::Decimal::from_str(\"0.01234\").unwrap(),\n    \"CAST(12.34 AS DECIMAL(4, 2))\" == sqlx::types::Decimal::from_str(\"12.34\").unwrap(),\n    \"CAST(12345.6789 AS DECIMAL(9, 4))\" == sqlx::types::Decimal::from_str(\"12345.6789\").unwrap(),\n));\n\n#[cfg(feature = \"json\")]\nmod json_tests {\n    use serde_json::{json, Value as JsonValue};\n\n    use sqlx::types::Json;\n    use sqlx_test::test_type;\n\n    use super::*;\n\n    test_type!(json<JsonValue>(\n        MySql,\n        // MySQL 8.0.27 changed `<=>` to return an unsigned integer\n        \"SELECT CAST(CAST({0} AS BINARY) <=> CAST(? AS BINARY) AS SIGNED INTEGER), CAST({0} AS BINARY) as _2, ? as _3\",\n        \"'\\\"Hello, World\\\"'\" == json!(\"Hello, World\"),\n        \"'\\\"😎\\\"'\" == json!(\"😎\"),\n        \"'\\\"🙋‍♀️\\\"'\" == json!(\"🙋‍♀️\"),\n        \"'[\\\"Hello\\\",\\\"World!\\\"]'\" == json!([\"Hello\", \"World!\"])\n    ));\n\n    #[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq)]\n    struct Friend {\n        name: String,\n        age: u32,\n    }\n\n    test_type!(json_struct<Json<Friend>>(\n        MySql,\n        // MySQL 8.0.27 changed `<=>` to return an unsigned integer\n        \"SELECT CAST(CAST({0} AS BINARY) <=> CAST(? AS BINARY) AS SIGNED INTEGER), CAST({0} AS BINARY) as _2, ? as _3\",\n        \"\\'{\\\"name\\\":\\\"Joe\\\",\\\"age\\\":33}\\'\" == Json(Friend { name: \"Joe\".to_string(), age: 33 })\n    ));\n\n    // NOTE: This is testing recursive (and transparent) usage of the `Json` wrapper. You don't\n    //       need to wrap the Vec in Json<_> to make the example work.\n\n    #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]\n    struct Customer {\n        json_column: Json<Vec<i64>>,\n    }\n\n    test_type!(json_struct_json_column<Json<Customer>>(\n        MySql,\n        \"\\'{\\\"json_column\\\":[1,2]}\\'\" == Json(Customer { json_column: Json(vec![1, 2]) })\n    ));\n}\n\ntest_type!(test_arc<Arc<i32>>(MySql, \"1\" == Arc::new(1i32)));\ntest_type!(test_cow<Cow<'_, i32>>(MySql, \"1\" == Cow::<i32>::Owned(1i32)));\ntest_type!(test_box<Box<i32>>(MySql, \"1\" == Box::new(1i32)));\ntest_type!(test_rc<Rc<i32>>(MySql, \"1\" == Rc::new(1i32)));\n\ntest_type!(test_box_str<Box<str>>(MySql, \"'John'\" == Box::<str>::from(\"John\")));\ntest_type!(test_cow_str<Cow<'_, str>>(MySql, \"'Phil'\" == Cow::<'static, str>::from(\"Phil\")));\ntest_type!(test_arc_str<Arc<str>>(MySql, \"'1234'\" == Arc::<str>::from(\"1234\")));\ntest_type!(test_rc_str<Rc<str>>(MySql, \"'5678'\" == Rc::<str>::from(\"5678\")));\n\ntest_prepared_type!(test_box_slice<Box<[u8]>>(MySql, \"X'01020304'\" == Box::<[u8]>::from([1,2,3,4])));\ntest_prepared_type!(test_cow_slice<Cow<'_, [u8]>>(MySql, \"X'01020304'\" == Cow::<'static, [u8]>::from(&[1,2,3,4])));\ntest_prepared_type!(test_arc_slice<Arc<[u8]>>(MySql, \"X'01020304'\" == Arc::<[u8]>::from([1,2,3,4])));\ntest_prepared_type!(test_rc_slice<Rc<[u8]>>(MySql, \"X'01020304'\" == Rc::<[u8]>::from([1,2,3,4])));\n\n#[sqlx_macros::test]\nasync fn test_bits() -> anyhow::Result<()> {\n    let mut conn = new::<MySql>().await?;\n\n    conn.execute(\n        r#\"\nCREATE TEMPORARY TABLE with_bits (\n    id INT PRIMARY KEY AUTO_INCREMENT,\n    value_1 BIT(1) NOT NULL,\n    value_n BIT(64) NOT NULL\n);\n    \"#,\n    )\n    .await?;\n\n    sqlx::query(\"INSERT INTO with_bits (value_1, value_n) VALUES (?, ?)\")\n        .bind(1_u8)\n        .bind(510202_u32)\n        .execute(&mut conn)\n        .await?;\n\n    // BINARY\n    let (v1, vn): (u8, u64) = sqlx::query_as(\"SELECT value_1, value_n FROM with_bits\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(v1, 1);\n    assert_eq!(vn, 510202);\n\n    // TEXT\n    let row = conn\n        .fetch_one(\"SELECT value_1, value_n FROM with_bits\")\n        .await?;\n    let v1: u8 = row.try_get(0)?;\n    let vn: u64 = row.try_get(1)?;\n\n    assert_eq!(v1, 1);\n    assert_eq!(vn, 510202);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_text_adapter() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n    struct Login {\n        user_id: i32,\n        socket_addr: Text<SocketAddr>,\n        #[cfg(feature = \"time\")]\n        login_at: time::OffsetDateTime,\n    }\n\n    let mut conn = new::<MySql>().await?;\n\n    conn.execute(\n        r#\"\nCREATE TEMPORARY TABLE user_login (\n    user_id INT PRIMARY KEY AUTO_INCREMENT,\n    socket_addr TEXT NOT NULL,\n    login_at TIMESTAMP NOT NULL\n);\n    \"#,\n    )\n    .await?;\n\n    let user_id = 1234;\n    let socket_addr: SocketAddr = \"198.51.100.47:31790\".parse().unwrap();\n\n    sqlx::query(\"INSERT INTO user_login (user_id, socket_addr, login_at) VALUES (?, ?, NOW())\")\n        .bind(user_id)\n        .bind(Text(socket_addr))\n        .execute(&mut conn)\n        .await?;\n\n    let last_login: Login =\n        sqlx::query_as(\"SELECT * FROM user_login ORDER BY login_at DESC LIMIT 1\")\n            .fetch_one(&mut conn)\n            .await?;\n\n    assert_eq!(last_login.user_id, user_id);\n    assert_eq!(*last_login.socket_addr, socket_addr);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/Dockerfile",
    "content": "ARG VERSION\nFROM postgres:${VERSION}-alpine\n\n# Copy SSL certificate (and key)\nCOPY certs/server.crt /var/lib/postgresql/server.crt\nCOPY certs/ca.crt /var/lib/postgresql/ca.crt\nCOPY certs/keys/server.key /var/lib/postgresql/server.key\nCOPY postgres/pg_hba.conf /var/lib/postgresql/pg_hba.conf\n\n# Fix permissions\nRUN chown 70:70 /var/lib/postgresql/server.crt /var/lib/postgresql/server.key\nRUN chmod 0600 /var/lib/postgresql/server.crt /var/lib/postgresql/server.key\n"
  },
  {
    "path": "tests/postgres/derives.rs",
    "content": "use futures_util::TryStreamExt;\nuse sqlx::postgres::types::PgRange;\nuse sqlx::{Connection, Executor, FromRow, Postgres};\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse sqlx_postgres::PgHasArrayType;\nuse sqlx_test::{new, test_type};\nuse std::fmt::Debug;\nuse std::ops::Bound;\n\n// Transparent types are rust-side wrappers over DB types\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct Transparent(i32);\n\n// Also possible for single-field named structs\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct TransparentNamed {\n    field: i32,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n// https://github.com/launchbadge/sqlx/issues/2611\n// Previously, the derive would generate a `PgHasArrayType` impl that errored on an\n// impossible-to-satisfy `where` bound. This attribute allows the user to opt-out.\n#[sqlx(transparent, no_pg_array)]\nstruct TransparentArray(Vec<i64>);\n\n#[sqlx_macros::test]\nasync fn test_transparent_slice_to_array() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let values = vec![Transparent(1), Transparent(2), Transparent(3)];\n\n    sqlx::query(\"SELECT 2 = ANY($1);\")\n        .bind(&values)\n        .fetch_one(&mut conn)\n        .await?;\n\n    Ok(())\n}\n\n// \"Weak\" enums map to an integer type indicated by #[repr]\n#[derive(PartialEq, Copy, Clone, Debug, sqlx::Type)]\n#[repr(i32)]\nenum Weak {\n    One = 0,\n    Two = 2,\n    Three = 4,\n}\n\n// \"Strong\" enums can map to TEXT (25)\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"text\")]\n#[sqlx(rename_all = \"lowercase\")]\nenum Strong {\n    One,\n    Two,\n\n    #[sqlx(rename = \"four\")]\n    Three,\n}\n\n// rename_all variants\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_lower\")]\n#[sqlx(rename_all = \"lowercase\")]\nenum ColorLower {\n    Red,\n    Green,\n    Blue,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_snake\")]\n#[sqlx(rename_all = \"snake_case\")]\nenum ColorSnake {\n    RedGreen,\n    BlueBlack,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_upper\")]\n#[sqlx(rename_all = \"UPPERCASE\")]\nenum ColorUpper {\n    Red,\n    Green,\n    Blue,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_screaming_snake\")]\n#[sqlx(rename_all = \"SCREAMING_SNAKE_CASE\")]\nenum ColorScreamingSnake {\n    RedGreen,\n    BlueBlack,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_kebab_case\")]\n#[sqlx(rename_all = \"kebab-case\")]\nenum ColorKebabCase {\n    RedGreen,\n    BlueBlack,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_mixed_case\")]\n#[sqlx(rename_all = \"camelCase\")]\nenum ColorCamelCase {\n    RedGreen,\n    BlueBlack,\n}\n\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"color_camel_case\")]\n#[sqlx(rename_all = \"PascalCase\")]\nenum ColorPascalCase {\n    RedGreen,\n    BlueBlack,\n}\n\n// \"Strong\" enum can map to a custom type\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"mood\")]\n#[sqlx(rename_all = \"lowercase\")]\nenum Mood {\n    Ok,\n    Happy,\n    Sad,\n}\n\n// Records must map to a custom type\n// Note that all types are types in Postgres\n#[derive(PartialEq, Debug, sqlx::Type)]\n#[sqlx(type_name = \"inventory_item\")]\nstruct InventoryItem {\n    name: String,\n    supplier_id: Option<i32>,\n    price: Option<i64>,\n}\n\n// Custom range type\n#[derive(sqlx::Type, Debug, PartialEq)]\n#[sqlx(type_name = \"float_range\")]\nstruct FloatRange(PgRange<f64>);\n\n// Custom domain type\n#[derive(sqlx::Type, Debug)]\n#[sqlx(type_name = \"int4rangeL0pC\")]\nstruct RangeInclusive(PgRange<i32>);\n\ntest_type!(transparent_tuple<Transparent>(Postgres,\n    \"0\" == Transparent(0),\n    \"23523\" == Transparent(23523)\n));\n\ntest_type!(transparent_named<TransparentNamed>(Postgres,\n    \"0\" == TransparentNamed { field: 0 },\n    \"23523\" == TransparentNamed { field: 23523 },\n));\n\ntest_type!(transparent_array<TransparentArray>(Postgres,\n    \"'{}'::int8[]\" == TransparentArray(vec![]),\n    \"'{ 23523, 123456, 789 }'::int8[]\" == TransparentArray(vec![23523, 123456, 789])\n));\n\ntest_type!(weak_enum<Weak>(Postgres,\n    \"0::int4\" == Weak::One,\n    \"2::int4\" == Weak::Two,\n    \"4::int4\" == Weak::Three,\n));\n\ntest_type!(weak_enum_array<Vec<Weak>>(Postgres,\n    \"'{0, 2, 4}'::int4[]\" == vec![Weak::One, Weak::Two, Weak::Three],\n));\n\ntest_type!(strong_enum<Strong>(Postgres,\n    \"'one'::text\" == Strong::One,\n    \"'two'::text\" == Strong::Two,\n    \"'four'::text\" == Strong::Three,\n));\n\ntest_type!(strong_enum_array<Vec<Strong>>(Postgres,\n    \"ARRAY['one', 'two', 'four']\" == vec![Strong::One, Strong::Two, Strong::Three],\n));\n\ntest_type!(floatrange<FloatRange>(Postgres,\n    \"'[1.234, 5.678]'::float_range\" == FloatRange(PgRange::from((Bound::Included(1.234), Bound::Included(5.678)))),\n));\n\n#[sqlx_macros::test]\nasync fn test_enum_type() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\n        r#\"\nDROP TABLE IF EXISTS people;\n\nDROP TYPE IF EXISTS mood CASCADE;\n\nCREATE TYPE mood AS ENUM ( 'ok', 'happy', 'sad' );\n\nDROP TYPE IF EXISTS color_lower CASCADE;\nDROP TYPE IF EXISTS color_snake CASCADE;\nDROP TYPE IF EXISTS color_upper CASCADE;\nDROP TYPE IF EXISTS color_screaming_snake CASCADE;\nDROP TYPE IF EXISTS color_kebab_case CASCADE;\nDROP TYPE IF EXISTS color_mixed_case CASCADE;\nDROP TYPE IF EXISTS color_camel_case CASCADE;\n\n\nCREATE TYPE color_lower AS ENUM ( 'red', 'green', 'blue' );\nCREATE TYPE color_snake AS ENUM ( 'red_green', 'blue_black' );\nCREATE TYPE color_upper AS ENUM ( 'RED', 'GREEN', 'BLUE' );\nCREATE TYPE color_screaming_snake AS ENUM ( 'RED_GREEN', 'BLUE_BLACK' );\nCREATE TYPE color_kebab_case AS ENUM ( 'red-green', 'blue-black' );\nCREATE TYPE color_mixed_case AS ENUM ( 'redGreen', 'blueBlack' );\nCREATE TYPE color_camel_case AS ENUM ( 'RedGreen', 'BlueBlack' );\n\n\nCREATE TABLE people (\n    id      serial PRIMARY KEY,\n    mood    mood not null\n);\n    \"#,\n    )\n    .await?;\n\n    // Drop and re-acquire the connection\n    conn.close().await?;\n    let mut conn = new::<Postgres>().await?;\n\n    // Select from table test\n    let (people_id,): (i32,) = sqlx::query_as(\n        \"\nINSERT INTO people (mood)\nVALUES ($1)\nRETURNING id\n        \",\n    )\n    .bind(Mood::Sad)\n    .fetch_one(&mut conn)\n    .await?;\n\n    // Drop and re-acquire the connection\n    conn.close().await?;\n    let mut conn = new::<Postgres>().await?;\n\n    #[derive(sqlx::FromRow)]\n    struct PeopleRow {\n        id: i32,\n        mood: Mood,\n    }\n\n    let rec: PeopleRow = sqlx::query_as(\n        \"\nSELECT id, mood FROM people WHERE id = $1\n            \",\n    )\n    .bind(people_id)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(rec.id, people_id);\n    assert_eq!(rec.mood, Mood::Sad);\n\n    // Drop and re-acquire the connection\n    conn.close().await?;\n    let mut conn = new::<Postgres>().await?;\n\n    let stmt = format!(\"SELECT id, mood FROM people WHERE id = {people_id}\");\n    dbg!(&stmt);\n\n    let mut cursor = conn.fetch(AssertSqlSafe(stmt));\n\n    let row = cursor.try_next().await?.unwrap();\n    let rec = PeopleRow::from_row(&row)?;\n\n    assert_eq!(rec.id, people_id);\n    assert_eq!(rec.mood, Mood::Sad);\n\n    drop(cursor);\n\n    // Normal type equivalency test\n\n    let rec: (bool, Mood) = sqlx::query_as(\n        \"\n    SELECT $1 = 'happy'::mood, $1\n            \",\n    )\n    .bind(&Mood::Happy)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, Mood::Happy);\n\n    let rec: (bool, ColorLower) = sqlx::query_as(\n        \"\n    SELECT $1 = 'green'::color_lower, $1\n            \",\n    )\n    .bind(&ColorLower::Green)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorLower::Green);\n\n    let rec: (bool, ColorSnake) = sqlx::query_as(\n        \"\n    SELECT $1 = 'red_green'::color_snake, $1\n            \",\n    )\n    .bind(&ColorSnake::RedGreen)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorSnake::RedGreen);\n\n    let rec: (bool, ColorUpper) = sqlx::query_as(\n        \"\n    SELECT $1 = 'RED'::color_upper, $1\n            \",\n    )\n    .bind(&ColorUpper::Red)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorUpper::Red);\n\n    let rec: (bool, ColorScreamingSnake) = sqlx::query_as(\n        \"\n    SELECT $1 = 'RED_GREEN'::color_screaming_snake, $1\n            \",\n    )\n    .bind(&ColorScreamingSnake::RedGreen)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorScreamingSnake::RedGreen);\n\n    let rec: (bool, ColorKebabCase) = sqlx::query_as(\n        \"\n    SELECT $1 = 'red-green'::color_kebab_case, $1\n            \",\n    )\n    .bind(&ColorKebabCase::RedGreen)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorKebabCase::RedGreen);\n\n    let rec: (bool, ColorCamelCase) = sqlx::query_as(\n        \"\n    SELECT $1 = 'redGreen'::color_mixed_case, $1\n            \",\n    )\n    .bind(&ColorCamelCase::RedGreen)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorCamelCase::RedGreen);\n\n    let rec: (bool, ColorPascalCase) = sqlx::query_as(\n        \"\n    SELECT $1 = 'RedGreen'::color_camel_case, $1\n            \",\n    )\n    .bind(&ColorPascalCase::RedGreen)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, ColorPascalCase::RedGreen);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_record_type() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let value = InventoryItem {\n        name: \"fuzzy dice\".to_owned(),\n        supplier_id: Some(42),\n        price: Some(199),\n    };\n\n    let rec: (bool, InventoryItem) = sqlx::query_as(\n        \"\nSELECT $1 = ROW('fuzzy dice', 42, 199)::inventory_item, $1\n        \",\n    )\n    .bind(&value)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert!(rec.0);\n    assert_eq!(rec.1, value);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_new_type() {\n    struct NewType(i32);\n\n    impl From<i32> for NewType {\n        fn from(value: i32) -> Self {\n            NewType(value)\n        }\n    }\n\n    let mut conn = new::<Postgres>().await.unwrap();\n\n    struct NewTypeRow {\n        id: NewType,\n    }\n\n    let res = sqlx::query_as!(NewTypeRow, r#\"SELECT 1 as \"id!\"\"#)\n        .fetch_one(&mut conn)\n        .await\n        .unwrap();\n    assert_eq!(res.id.0, 1);\n\n    struct NormalRow {\n        id: i32,\n    }\n\n    let res = sqlx::query_as!(NormalRow, r#\"SELECT 1 as \"id!\"\"#)\n        .fetch_one(&mut conn)\n        .await\n        .unwrap();\n\n    assert_eq!(res.id, 1);\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_from_row() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    #[derive(sqlx::FromRow)]\n    struct Account {\n        id: i32,\n        name: String,\n    }\n\n    let account: Account = sqlx::query_as(\n        \"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1\",\n    )\n    .bind(1_i32)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, \"Herp Derpinson\");\n\n    // A _single_ lifetime may be used but only when using the lowest-level API currently (Query::fetch)\n\n    #[derive(sqlx::FromRow)]\n    struct RefAccount<'a> {\n        id: i32,\n        name: &'a str,\n    }\n\n    let mut cursor = sqlx::query(\n        \"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1\",\n    )\n    .bind(1_i32)\n    .fetch(&mut conn);\n\n    let row = cursor.try_next().await?.unwrap();\n    let account = RefAccount::from_row(&row)?;\n\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, \"Herp Derpinson\");\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_from_row_with_keyword() -> anyhow::Result<()> {\n    #[derive(Debug, sqlx::FromRow)]\n    struct AccountKeyword {\n        r#type: i32,\n        r#static: String,\n        r#let: Option<String>,\n        r#struct: Option<String>,\n        name: Option<String>,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let account: AccountKeyword = sqlx::query_as(\n        r#\"SELECT * from (VALUES (1, 'foo', 'bar', null, null)) accounts(type, static, let, struct, name)\"#\n    )\n    .fetch_one(&mut conn)\n    .await?;\n    println!(\"{account:?}\");\n\n    assert_eq!(1, account.r#type);\n    assert_eq!(\"foo\", account.r#static);\n    assert_eq!(None, account.r#struct);\n    assert_eq!(Some(\"bar\".to_owned()), account.r#let);\n    assert_eq!(None, account.name);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_from_row_with_rename() -> anyhow::Result<()> {\n    #[derive(Debug, sqlx::FromRow)]\n    struct AccountKeyword {\n        #[sqlx(rename = \"type\")]\n        own_type: i32,\n\n        #[sqlx(rename = \"static\")]\n        my_static: String,\n\n        #[sqlx(rename = \"let\")]\n        custom_let: Option<String>,\n\n        #[sqlx(rename = \"struct\")]\n        def_struct: Option<String>,\n\n        name: Option<String>,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let account: AccountKeyword = sqlx::query_as(\n        r#\"SELECT * from (VALUES (1, 'foo', 'bar', null, null)) accounts(type, static, let, struct, name)\"#\n    )\n    .fetch_one(&mut conn)\n    .await?;\n    println!(\"{account:?}\");\n\n    assert_eq!(1, account.own_type);\n    assert_eq!(\"foo\", account.my_static);\n    assert_eq!(None, account.def_struct);\n    assert_eq!(Some(\"bar\".to_owned()), account.custom_let);\n    assert_eq!(None, account.name);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_from_row_with_rename_all() -> anyhow::Result<()> {\n    #[derive(Debug, sqlx::FromRow)]\n    #[sqlx(rename_all = \"camelCase\")]\n    struct AccountKeyword {\n        user_id: i32,\n        user_name: String,\n        user_surname: String,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let account: AccountKeyword = sqlx::query_as(\n        r#\"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(\"userId\", \"userName\", \"userSurname\")\"#,\n    )\n    .fetch_one(&mut conn)\n    .await?;\n    println!(\"{account:?}\");\n\n    assert_eq!(1, account.user_id);\n    assert_eq!(\"foo\", account.user_name);\n    assert_eq!(\"bar\", account.user_surname);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_from_row_tuple() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    #[derive(Debug, sqlx::FromRow)]\n    struct Account(i32, String);\n\n    let account: Account = sqlx::query_as(\n        \"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1\",\n    )\n    .bind(1_i32)\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(account.0, 1);\n    assert_eq!(account.1, \"Herp Derpinson\");\n\n    // A _single_ lifetime may be used but only when using the lowest-level API currently (Query::fetch)\n\n    #[derive(sqlx::FromRow)]\n    struct RefAccount<'a>(i32, &'a str);\n\n    let mut cursor = sqlx::query(\n        \"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1\",\n    )\n    .bind(1_i32)\n    .fetch(&mut conn);\n\n    let row = cursor.try_next().await?.unwrap();\n    let account = RefAccount::from_row(&row)?;\n\n    assert_eq!(account.0, 1);\n    assert_eq!(account.1, \"Herp Derpinson\");\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_default() -> anyhow::Result<()> {\n    #[derive(Debug, sqlx::FromRow)]\n    struct HasDefault {\n        not_default: i32,\n        #[sqlx(default)]\n        default: Option<i32>,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let has_default: HasDefault = sqlx::query_as(r#\"SELECT 1 AS not_default\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    println!(\"{has_default:?}\");\n\n    assert_eq!(has_default.not_default, 1);\n    assert_eq!(has_default.default, None);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_struct_default() -> anyhow::Result<()> {\n    #[derive(Debug, sqlx::FromRow)]\n    #[sqlx(default)]\n    struct HasDefault {\n        not_default: Option<i32>,\n        default_a: Option<String>,\n        default_b: Option<i32>,\n    }\n\n    impl Default for HasDefault {\n        fn default() -> HasDefault {\n            HasDefault {\n                not_default: None,\n                default_a: None,\n                default_b: Some(0),\n            }\n        }\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let has_default: HasDefault = sqlx::query_as(r#\"SELECT 1 AS not_default\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    println!(\"{has_default:?}\");\n\n    assert_eq!(has_default.not_default, Some(1));\n    assert_eq!(has_default.default_a, None);\n    assert_eq!(has_default.default_b, Some(0));\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_flatten() -> anyhow::Result<()> {\n    #[derive(Debug, Default, sqlx::FromRow)]\n    struct AccountDefault {\n        default: Option<i32>,\n    }\n\n    #[derive(Debug, sqlx::FromRow)]\n    struct UserInfo {\n        name: String,\n        surname: String,\n    }\n\n    #[derive(Debug, sqlx::FromRow)]\n    struct AccountKeyword {\n        id: i32,\n        #[sqlx(flatten)]\n        info: UserInfo,\n        #[sqlx(default)]\n        #[sqlx(flatten)]\n        default: AccountDefault,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let account: AccountKeyword = sqlx::query_as(\n        r#\"SELECT * from (VALUES (1, 'foo', 'bar')) accounts(\"id\", \"name\", \"surname\")\"#,\n    )\n    .fetch_one(&mut conn)\n    .await?;\n    println!(\"{account:?}\");\n\n    assert_eq!(1, account.id);\n    assert_eq!(\"foo\", account.info.name);\n    assert_eq!(\"bar\", account.info.surname);\n    assert_eq!(None, account.default.default);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_skip() -> anyhow::Result<()> {\n    #[derive(Debug, Default, sqlx::FromRow)]\n    struct AccountDefault {\n        default: Option<i32>,\n    }\n\n    #[derive(Debug, sqlx::FromRow)]\n    struct AccountKeyword {\n        id: i32,\n        #[sqlx(skip)]\n        default: AccountDefault,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let account: AccountKeyword = sqlx::query_as(r#\"SELECT * from (VALUES (1)) accounts(\"id\")\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    println!(\"{account:?}\");\n\n    assert_eq!(1, account.id);\n    assert_eq!(None, account.default.default);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_enum_with_schema() -> anyhow::Result<()> {\n    #[derive(Debug, PartialEq, Eq, sqlx::Type)]\n    #[sqlx(type_name = \"foo.\\\"Foo\\\"\")]\n    enum Foo {\n        Bar,\n        Baz,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let foo: Foo = sqlx::query_scalar(\"SELECT $1::foo.\\\"Foo\\\"\")\n        .bind(Foo::Bar)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo, Foo::Bar);\n\n    let foo: Foo = sqlx::query_scalar(\"SELECT $1::foo.\\\"Foo\\\"\")\n        .bind(Foo::Baz)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo, Foo::Baz);\n\n    let foos: Vec<Foo> = sqlx::query_scalar(\"SELECT ARRAY[$1::foo.\\\"Foo\\\", $2::foo.\\\"Foo\\\"]\")\n        .bind(Foo::Bar)\n        .bind(Foo::Baz)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foos, [Foo::Bar, Foo::Baz]);\n\n    Ok(())\n}\n\n#[cfg(feature = \"macros\")]\n#[sqlx_macros::test]\nasync fn test_from_row_hygiene() -> anyhow::Result<()> {\n    // A field named `row` previously would shadow the `row` parameter of `FromRow::from_row()`:\n    // https://github.com/launchbadge/sqlx/issues/3344\n    #[derive(Debug, sqlx::FromRow)]\n    pub struct Foo {\n        pub row: i32,\n        pub bar: i32,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let foo: Foo = sqlx::query_as(\"SELECT 1234 as row, 5678 as bar\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(foo.row, 1234);\n    assert_eq!(foo.bar, 5678);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_custom_pg_array() -> anyhow::Result<()> {\n    #[derive(sqlx::Type)]\n    #[sqlx(no_pg_array)]\n    pub struct User {\n        pub id: i32,\n        pub username: String,\n    }\n\n    impl PgHasArrayType for User {\n        fn array_type_info() -> sqlx::postgres::PgTypeInfo {\n            sqlx::postgres::PgTypeInfo::array_of(\"User\")\n        }\n    }\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_record_array_type() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\n        r#\"\nDROP TABLE IF EXISTS responses;\n\nDROP TYPE IF EXISTS http_response CASCADE;\nDROP TYPE IF EXISTS header_pair CASCADE;\n\nCREATE TYPE header_pair AS (\n    name TEXT,\n    value TEXT\n);\n\nCREATE TYPE http_response AS (\n    headers header_pair[]\n);\n\nCREATE TABLE responses (\n    response http_response NOT NULL\n);\n    \"#,\n    )\n    .await?;\n\n    #[derive(Debug, sqlx::Type)]\n    #[sqlx(type_name = \"http_response\")]\n    struct HttpResponseRecord {\n        headers: Vec<HeaderPairRecord>,\n    }\n\n    #[derive(Debug, sqlx::Type)]\n    #[sqlx(type_name = \"header_pair\")]\n    struct HeaderPairRecord {\n        name: String,\n        value: String,\n    }\n\n    let value = HttpResponseRecord {\n        headers: vec![\n            HeaderPairRecord {\n                name: \"Content-Type\".to_owned(),\n                value: \"text/html; charset=utf-8\".to_owned(),\n            },\n            HeaderPairRecord {\n                name: \"Cache-Control\".to_owned(),\n                value: \"max-age=0\".to_owned(),\n            },\n        ],\n    };\n\n    sqlx::query(\n        \"\nINSERT INTO responses (response)\nVALUES ($1)\n        \",\n    )\n    .bind(&value)\n    .execute(&mut conn)\n    .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/describe.rs",
    "content": "use sqlx::{postgres::Postgres, Column, Executor, SqlSafeStr, TypeInfo};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_describes_simple() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let d = conn.describe(\"SELECT * FROM tweet\".into_sql_str()).await?;\n\n    assert_eq!(d.columns()[0].name(), \"id\");\n    assert_eq!(d.columns()[1].name(), \"created_at\");\n    assert_eq!(d.columns()[2].name(), \"text\");\n    assert_eq!(d.columns()[3].name(), \"owner_id\");\n\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.nullable(1), Some(false));\n    assert_eq!(d.nullable(2), Some(false));\n    assert_eq!(d.nullable(3), Some(true));\n\n    assert_eq!(d.columns()[0].type_info().name(), \"INT8\");\n    assert_eq!(d.columns()[1].type_info().name(), \"TIMESTAMPTZ\");\n    assert_eq!(d.columns()[2].type_info().name(), \"TEXT\");\n    assert_eq!(d.columns()[3].type_info().name(), \"INT8\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_expression() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let d = conn.describe(\"SELECT 1::int8 + 10\".into_sql_str()).await?;\n\n    // ?column? will cause the macro to emit an error ad ask the user to explicitly name the type\n    assert_eq!(d.columns()[0].name(), \"?column?\");\n\n    // postgres cannot infer nullability from an expression\n    // this will cause the macro to emit `Option<_>`\n    assert_eq!(d.nullable(0), None);\n    assert_eq!(d.columns()[0].type_info().name(), \"INT8\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_enum() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let d = conn\n        .describe(\"SELECT 'open'::status as _1\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns()[0].name(), \"_1\");\n\n    let ty = d.columns()[0].type_info();\n\n    assert_eq!(ty.name(), \"status\");\n\n    assert_eq!(\n        format!(\"{:?}\", ty.kind()),\n        r#\"Enum([\"new\", \"open\", \"closed\"])\"#\n    );\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_record() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let d = conn\n        .describe(\"SELECT (true, 10::int2)\".into_sql_str())\n        .await?;\n\n    let ty = d.columns()[0].type_info();\n    assert_eq!(ty.name(), \"RECORD\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_composite() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let d = conn\n        .describe(\"SELECT ROW('name',10,500)::inventory_item\".into_sql_str())\n        .await?;\n\n    let ty = d.columns()[0].type_info();\n\n    assert_eq!(ty.name(), \"inventory_item\");\n\n    assert_eq!(\n        format!(\"{:?}\", ty.kind()),\n        r#\"Composite([(\"name\", PgTypeInfo(Text)), (\"supplier_id\", PgTypeInfo(Int4)), (\"price\", PgTypeInfo(Int8))])\"#\n    );\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/error.rs",
    "content": "use sqlx::{error::ErrorKind, postgres::Postgres, Connection, Error};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_fails_with_unique_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO tweet(id, text, owner_id) VALUES (1, 'Foo', 1);\")\n        .execute(&mut *tx)\n        .await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"INSERT INTO tweet VALUES (1, NOW(), 'Foo', 1);\")\n        .execute(&mut *tx)\n        .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::UniqueViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_foreign_key_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO tweet_reply (tweet_id, text) VALUES (1, 'Reply!');\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::ForeignKeyViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_not_null_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"INSERT INTO tweet (text) VALUES (null);\")\n        .execute(&mut *tx)\n        .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::NotNullViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_check_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO products VALUES (1, 'Product 1', 0);\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::CheckViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_exclude_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO circles VALUES (circle('(0,0)'::point, 5.0));\")\n        .execute(&mut *tx)\n        .await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO circles VALUES (circle('(0,2.0)'::point, 2.0));\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::ExclusionViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_begin_failed() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let res = conn.begin_with(\"SELECT * FROM tweet\").await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::BeginFailed), \"{err:?}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_invalid_save_point_statement() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut txn = conn.begin().await?;\n    let txn_conn = sqlx::Acquire::acquire(&mut txn).await?;\n    let res = txn_conn.begin_with(\"BEGIN\").await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::InvalidSavePointStatement), \"{err}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/fixtures/comments.sql",
    "content": "insert into comment(comment_id, post_id, user_id, content, created_at)\nvalues ('fbbbb7dc-dc6f-4649-b663-8d3636035164',\n        '252c1d98-a9b0-4f18-8298-e59058bdfe16',\n        '297923c5-a83c-4052-bab0-030887154e52',\n        'lol bet ur still bad, 1v1 me',\n        now() + '50 minutes ago'::interval),\n       ('cb7612a2-cff4-4e3e-a768-055f01f25dc4',\n        '252c1d98-a9b0-4f18-8298-e59058bdfe16',\n        '297923c5-a83c-4052-bab0-030887154e52',\n        'you''re on!',\n        now() + '45 minutes ago'::interval),\n       ('f2164fcc-a770-4f52-8714-d9cc6a1c89cf',\n        '844265f7-2472-4689-9a2e-b21f40dbf401',\n        '297923c5-a83c-4052-bab0-030887154e52',\n        'lol you''re just mad you lost :P',\n        now() + '15 minutes ago'::interval);\n"
  },
  {
    "path": "tests/postgres/fixtures/posts.sql",
    "content": "insert into post(post_id, user_id, content, created_at)\nvalues\n       (\n        '252c1d98-a9b0-4f18-8298-e59058bdfe16',\n        '6592b7c0-b531-4613-ace5-94246b7ce0c3',\n        'This new computer is lightning-fast!',\n        now() + '1 hour ago'::interval\n        ),\n       (\n        '844265f7-2472-4689-9a2e-b21f40dbf401',\n        '6592b7c0-b531-4613-ace5-94246b7ce0c3',\n        '@alice is a haxxor :(',\n        now() + '30 minutes ago'::interval\n        );\n"
  },
  {
    "path": "tests/postgres/fixtures/rustsec/2024_0363.sql",
    "content": "-- https://rustsec.org/advisories/RUSTSEC-2024-0363.html\n-- https://github.com/launchbadge/sqlx/issues/3440\nCREATE TABLE injection_target(id BIGSERIAL PRIMARY KEY, message TEXT);\nINSERT INTO injection_target(message) VALUES ('existing value');\n"
  },
  {
    "path": "tests/postgres/fixtures/users.sql",
    "content": "insert into \"user\"(user_id, username)\nvalues ('6592b7c0-b531-4613-ace5-94246b7ce0c3', 'alice'), ('297923c5-a83c-4052-bab0-030887154e52', 'bob');\n"
  },
  {
    "path": "tests/postgres/macros.rs",
    "content": "use sqlx::{Connection, PgConnection, Postgres, Transaction};\nuse sqlx_postgres::types::PgHstore;\nuse sqlx_test::new;\n\nuse futures_util::TryStreamExt;\n\n#[sqlx_macros::test]\nasync fn test_query() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let account = sqlx::query!(\n        \"SELECT * from (VALUES (1, 'Herp Derpinson')) accounts(id, name) where id = $1\",\n        1i32\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(account.id, Some(1));\n    assert_eq!(account.name.as_deref(), Some(\"Herp Derpinson\"));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_non_null() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    let _ = sqlx::query!(\"INSERT INTO tweet (text) VALUES ('Hello')\")\n        .execute(&mut *tx)\n        .await?;\n\n    let row = sqlx::query!(\"SELECT id, text, owner_id FROM tweet LIMIT 1\")\n        .fetch_one(&mut *tx)\n        .await?;\n\n    assert!(row.id > 0);\n    assert_eq!(row.text, \"Hello\");\n    assert_eq!(row.owner_id, None);\n\n    // let the transaction rollback so we don't actually insert the tweet\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_no_result() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    let _ = sqlx::query!(\"DELETE FROM tweet\").execute(&mut *tx).await?;\n\n    // let the transaction rollback so we don't actually delete the tweets\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_text_var_char_char_n() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // TEXT\n    // we cannot infer nullability from an expression\n    let rec = sqlx::query!(\"SELECT 'Hello'::text as greeting\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(rec.greeting.as_deref(), Some(\"Hello\"));\n\n    // VARCHAR(N)\n\n    let rec = sqlx::query!(\"SELECT 'Hello'::varchar(5) as greeting\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(rec.greeting.as_deref(), Some(\"Hello\"));\n\n    // CHAR(N)\n\n    let rec = sqlx::query!(\"SELECT 'Hello'::char(5) as greeting\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(rec.greeting.as_deref(), Some(\"Hello\"));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_void() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let _ = sqlx::query!(r#\"select pg_notify('chan', 'message')\"#)\n        .execute(&mut conn)\n        .await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_call_procedure() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let row = sqlx::query!(r#\"CALL forty_two(null)\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(row.forty_two, Some(42));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_file() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // keep trailing comma as a test\n    let account = sqlx::query_file!(\"tests/postgres/test-query.sql\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, Option::<String>::None);\n\n    Ok(())\n}\n\n#[derive(Debug)]\nstruct Account {\n    id: i32,\n    name: Option<String>,\n}\n\n#[sqlx_macros::test]\nasync fn test_query_as() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let name: Option<&str> = None;\n    let account = sqlx::query_as!(\n        Account,\n        r#\"SELECT id \"id!\", name from (VALUES (1, $1)) accounts(id, name)\"#,\n        name\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(1, account.id);\n    assert_eq!(None, account.name);\n\n    println!(\"{account:?}\");\n\n    Ok(())\n}\n\n#[derive(Debug)]\nstruct RawAccount {\n    r#type: i32,\n    name: Option<String>,\n}\n\n#[sqlx_macros::test]\nasync fn test_query_as_raw() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let account = sqlx::query_as!(\n        RawAccount,\n        r#\"SELECT type \"type!\", name from (VALUES (1, null)) accounts(type, name)\"#\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(None, account.name);\n    assert_eq!(1, account.r#type);\n\n    println!(\"{account:?}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_file_as() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let account = sqlx::query_file_as!(Account, \"tests/postgres/test-query.sql\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    println!(\"{account:?}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_scalar() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let id = sqlx::query_scalar!(\"select 1\").fetch_one(&mut conn).await?;\n    // nullability inference can't handle expressions\n    assert_eq!(id, Some(1i32));\n\n    // invalid column names are ignored\n    let id = sqlx::query_scalar!(r#\"select 1 as \"&foo\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(id, Some(1i32));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo!\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(id, 1i32);\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo?\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(1i32));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo: MyInt4\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(MyInt4(1i32)));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo?: MyInt4\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(MyInt4(1i32)));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo!: MyInt4\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt4(1i32));\n\n    let id: MyInt4 = sqlx::query_scalar!(r#\"select 1 as \"foo: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?\n        // don't hint that it should be `Option<MyInt4>`\n        .unwrap();\n\n    assert_eq!(id, MyInt4(1i32));\n\n    let id: MyInt4 = sqlx::query_scalar!(r#\"select 1 as \"foo?: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?\n        // don't hint that it should be `Option<MyInt4>`\n        .unwrap();\n\n    assert_eq!(id, MyInt4(1i32));\n\n    let id: MyInt4 = sqlx::query_scalar!(r#\"select 1 as \"foo!: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt4(1i32));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn query_by_string() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let string = \"Hello, world!\".to_string();\n    let ref tuple = (\"Hello, world!\".to_string(),);\n\n    let result = sqlx::query!(\n        \"SELECT * from (VALUES('Hello, world!')) strings(string)\\\n         where string in ($1, $2, $3, $4, $5, $6, $7)\",\n        string, // make sure we don't actually take ownership here\n        &string[..],\n        Some(&string),\n        Some(&string[..]),\n        Option::<String>::None,\n        string.clone(),\n        tuple.0 // make sure we're not trying to move out of a field expression\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(result.string, Some(string));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\n#[cfg(feature = \"bigdecimal\")]\nasync fn query_by_bigdecimal() -> anyhow::Result<()> {\n    use sqlx::types::BigDecimal;\n    let mut conn = new::<Postgres>().await?;\n\n    // this tests querying by a non-`Copy` type that doesn't have special reborrow semantics\n\n    let decimal = \"1234\".parse::<BigDecimal>()?;\n    let ref tuple = (\"51245.121232\".parse::<BigDecimal>()?,);\n\n    #[cfg_attr(feature = \"rust_decimal\", allow(deprecated))] // TODO: upgrade to `expect`\n    let result = sqlx::query!(\n        \"SELECT * from (VALUES(1234.0)) decimals(decimal)\\\n         where decimal in ($1, $2, $3, $4, $5, $6, $7)\",\n        decimal,  // make sure we don't actually take ownership here\n        &decimal, // allow query-by-reference\n        Some(&decimal),\n        Some(&decimal),\n        Option::<BigDecimal>::None,\n        decimal.clone(),\n        tuple.0 // make sure we're not trying to move out of a field expression\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(result.decimal, Some(decimal));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_nullable_err() -> anyhow::Result<()> {\n    #[allow(dead_code)]\n    #[derive(Debug)]\n    struct Account {\n        id: i32,\n        name: String,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let err = sqlx::query_as!(\n        Account,\n        r#\"SELECT id \"id!\", name \"name!\" from (VALUES (1, null::text)) accounts(id, name)\"#\n    )\n    .fetch_one(&mut conn)\n    .await\n    .unwrap_err();\n\n    if let sqlx::Error::ColumnDecode { source, .. } = &err {\n        if let Some(sqlx::error::UnexpectedNullError) = source.downcast_ref() {\n            return Ok(());\n        }\n    }\n\n    panic!(\"expected `UnexpectedNullError`, got {err}\")\n}\n\n#[sqlx_macros::test]\nasync fn test_many_args() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // previous implementation would only have supported 10 bind parameters\n    // (this is really gross to test in MySQL)\n    let rows = sqlx::query!(\n        \"SELECT * from unnest(array[$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12]::int[]) ids(id);\",\n        0i32, 1i32, 2i32, 3i32, 4i32, 5i32, 6i32, 7i32, 8i32, 9i32, 10i32, 11i32\n    )\n        .fetch_all(&mut conn)\n        .await?;\n\n    for (i, row) in rows.iter().enumerate() {\n        assert_eq!(Some(i as i32), row.id);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_array_from_slice() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let list: &[i32] = &[1, 2, 3, 4i32];\n\n    let result = sqlx::query!(\"SELECT $1::int[] as my_array\", list)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(result.my_array, Some(vec![1, 2, 3, 4]));\n\n    println!(\"result ID: {:?}\", result.my_array);\n\n    let account = sqlx::query!(\"SELECT ARRAY[4,3,2,1] as my_array\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(account.my_array, Some(vec![4, 3, 2, 1]));\n\n    println!(\"account ID: {:?}\", account.my_array);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn fetch_is_usable_issue_224() -> anyhow::Result<()> {\n    // ensures that the stream returned by `query::Map::fetch()` is usable with `TryStreamExt`\n    let mut conn = new::<Postgres>().await?;\n\n    let mut stream =\n        sqlx::query!(\"select * from generate_series(1, 3) as series(num);\").fetch(&mut conn);\n\n    // `num` is generated by a function so we can't assume it's non-null\n    assert_eq!(stream.try_next().await?.unwrap().num, Some(1));\n    assert_eq!(stream.try_next().await?.unwrap().num, Some(2));\n    assert_eq!(stream.try_next().await?.unwrap().num, Some(3));\n    assert!(stream.try_next().await?.is_none());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let record = sqlx::query!(r#\"select 1 as \"id!\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // workaround for https://github.com/launchbadge/sqlx/issues/367\n    // declare a `NOT NULL` column from a left-joined table to be nullable\n    let record = sqlx::query!(\n        r#\"select text as \"text?\" from (values (1)) foo(id) left join tweet on false\"#\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(record.text, None);\n\n    Ok(())\n}\n\nasync fn with_test_row<'a>(\n    conn: &'a mut PgConnection,\n) -> anyhow::Result<Transaction<'a, Postgres>> {\n    let mut transaction = conn.begin().await?;\n    sqlx::query!(\"INSERT INTO tweet(id, text, owner_id) VALUES (1, '#sqlx is pretty cool!', 1)\")\n        .execute(&mut *transaction)\n        .await?;\n    Ok(transaction)\n}\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct MyInt(i64);\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct MyInt4(i32);\n\nstruct Record {\n    id: MyInt,\n}\n\nstruct OptionalRecord {\n    id: Option<MyInt>,\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut conn = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as!(Record, r#\"select id as \"id: _\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    let record = sqlx::query_as!(OptionalRecord, r#\"select owner_id as \"id: _\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut conn = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as!(Record, r#\"select owner_id as \"id!: _\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut conn = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query_as!(OptionalRecord, r#\"select id as \"id?: _\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut conn = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query!(r#\"select id as \"id: MyInt\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    let record = sqlx::query!(r#\"select owner_id as \"id: MyInt\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut conn = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query!(r#\"select owner_id as \"id!: MyInt\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut conn = with_test_row(&mut conn).await?;\n\n    let record = sqlx::query!(r#\"select id as \"id?: MyInt\" from tweet\"#)\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_bind_arg_override_exact() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let my_int = MyInt4(1);\n\n    // this query should require a bind parameter override as we would otherwise expect the bind\n    // to be the same type\n    let record = sqlx::query!(\n        \"select * from (select 1::int4) records(id) where id = $1\",\n        my_int as MyInt4\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(record.id, Some(1i32));\n\n    // test that we're actually emitting the typecast by requiring the bound type to be the same\n    let record = sqlx::query!(\"select $1::int8 as id\", 1i32 as i64)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, Some(1i64));\n\n    // test the override with `Option`\n    let my_opt_int = Some(MyInt4(1));\n\n    let record = sqlx::query!(\n        \"select * from (select 1::int4) records(id) where id = $1\",\n        my_opt_int as Option<MyInt4>\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(record.id, Some(1i32));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_bind_arg_override_wildcard() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let my_int = MyInt4(1);\n\n    let record = sqlx::query!(\n        \"select * from (select 1::int4) records(id) where id = $1\",\n        my_int as _\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(record.id, Some(1i32));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_to_from_citext() -> anyhow::Result<()> {\n    // Ensure that the macros consider `CITEXT` to be compatible with `String` and friends\n\n    let mut conn = new::<Postgres>().await?;\n\n    let mut tx = conn.begin().await?;\n\n    let foo_in = \"Hello, world!\";\n\n    sqlx::query!(\"insert into test_citext(foo) values ($1)\", foo_in)\n        .execute(&mut *tx)\n        .await?;\n\n    let foo_out: String = sqlx::query_scalar!(\"select foo from test_citext\")\n        .fetch_one(&mut *tx)\n        .await?;\n\n    assert_eq!(foo_in, foo_out);\n\n    tx.rollback().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn pghstore_tests() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let mut store = PgHstore::default();\n    let stores = vec![store.clone(), store.clone()];\n\n    store.insert(\"key\".into(), Some(\"value\".to_string()));\n    sqlx::query!(\"         insert into mytable(f) values ($1)\", store)\n        .execute(&mut conn)\n        .await?;\n\n    sqlx::query!(\n        \"         insert into mytable(f) select * from unnest($1::hstore[])\",\n        &stores\n    )\n    .execute(&mut conn)\n    .await?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/migrate.rs",
    "content": "use sqlx::migrate::Migrator;\nuse sqlx::pool::PoolConnection;\nuse sqlx::postgres::{PgConnection, Postgres};\nuse sqlx::Executor;\nuse sqlx::Row;\nuse std::path::Path;\n\n#[sqlx::test(migrations = false)]\nasync fn simple(mut conn: PoolConnection<Postgres>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/postgres/migrations_simple\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: String = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_simple_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, \"110_suffix\");\n\n    // running it a 2nd time should still work\n    migrator.run(&mut conn).await?;\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = false)]\nasync fn reversible(mut conn: PoolConnection<Postgres>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/postgres/migrations_reversible\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 101);\n\n    // roll back nothing (last version)\n    migrator.undo(&mut conn, 20220721125033).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 101);\n\n    // roll back one version\n    migrator.undo(&mut conn, 20220721124650).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 100);\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = false)]\nasync fn no_tx(mut conn: PoolConnection<Postgres>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n    let migrator = Migrator::new(Path::new(\"tests/postgres/migrations_no_tx\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: String = conn\n        .fetch_one(\"SELECT datname FROM pg_database WHERE datname = 'test_db'\")\n        .await?\n        .get(0);\n\n    assert_eq!(res, \"test_db\");\n\n    Ok(())\n}\n\n/// Ensure that we have a clean initial state.\nasync fn clean_up(conn: &mut PgConnection) -> anyhow::Result<()> {\n    conn.execute(\"DROP DATABASE IF EXISTS test_db\").await.ok();\n    conn.execute(\"DROP TABLE migrations_simple_test\").await.ok();\n    conn.execute(\"DROP TABLE migrations_reversible_test\")\n        .await\n        .ok();\n    conn.execute(\"DROP TABLE _sqlx_migrations\").await.ok();\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/migrations/0_setup.sql",
    "content": "-- `gen_random_uuid()` wasn't added until Postgres 13\ncreate extension if not exists \"uuid-ossp\";\n"
  },
  {
    "path": "tests/postgres/migrations/1_user.sql",
    "content": "create table \"user\"\n(\n    user_id  uuid primary key default uuid_generate_v1mc(),\n    username text unique not null\n);\n"
  },
  {
    "path": "tests/postgres/migrations/2_post.sql",
    "content": "create table post (\n    post_id uuid primary key default uuid_generate_v1mc(),\n    user_id uuid not null references \"user\"(user_id),\n    content text not null,\n    created_at timestamptz default now()\n);\n\ncreate index on post(created_at desc);\n"
  },
  {
    "path": "tests/postgres/migrations/3_comment.sql",
    "content": "create table comment (\n    comment_id uuid primary key default uuid_generate_v1mc(),\n    post_id uuid not null references post(post_id),\n    user_id uuid not null references \"user\"(user_id),\n    content text not null,\n    created_at timestamptz not null default now()\n);\n\ncreate index on comment(created_at desc);\n"
  },
  {
    "path": "tests/postgres/migrations_no_tx/0_create_db.sql",
    "content": "-- no-transaction\n\nCREATE DATABASE test_db;\n"
  },
  {
    "path": "tests/postgres/migrations_reversible/20220721124650_add_table.down.sql",
    "content": "DROP TABLE migrations_reversible_test;\n"
  },
  {
    "path": "tests/postgres/migrations_reversible/20220721124650_add_table.up.sql",
    "content": "CREATE TABLE migrations_reversible_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_reversible_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/postgres/migrations_reversible/20220721125033_modify_column.down.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload - 1;\n"
  },
  {
    "path": "tests/postgres/migrations_reversible/20220721125033_modify_column.up.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload + 1;\n"
  },
  {
    "path": "tests/postgres/migrations_simple/20220721115250_add_test_table.sql",
    "content": "CREATE TABLE migrations_simple_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_simple_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/postgres/migrations_simple/20220721115524_convert_type.sql",
    "content": "-- Perform a tricky conversion of the payload.\n--\n-- This script will only succeed once and will fail if executed twice.\n\n-- set up temporary target column\nALTER TABLE migrations_simple_test\nADD some_payload_tmp TEXT;\n\n-- perform conversion\n-- This will fail if `some_payload` is already a string column due to the addition.\n-- We add a suffix after the addition to ensure that the SQL database does not silently cast the string back to an \n-- integer.\nUPDATE migrations_simple_test\nSET some_payload_tmp = CONCAT(CAST((some_payload + 10) AS TEXT), '_suffix');\n\n-- remove original column including the content\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload;\n\n-- prepare new payload column (nullable, so we can copy over the data)\nALTER TABLE migrations_simple_test\nADD some_payload TEXT;\n\n-- copy new values\nUPDATE migrations_simple_test\nSET some_payload = some_payload_tmp;\n\n-- \"freeze\" column\nALTER TABLE migrations_simple_test\nALTER COLUMN some_payload SET NOT NULL;\n\n-- clean up\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload_tmp;\n"
  },
  {
    "path": "tests/postgres/pg_hba.conf",
    "content": "# only needed for certificate authentication tests\n# omit host to prevent fallback to non certificate authentication\nlocal   all all     trust\nhostssl all all all cert\n"
  },
  {
    "path": "tests/postgres/postgres.rs",
    "content": "use futures_util::{Stream, StreamExt, TryStreamExt};\n\nuse sqlx::postgres::types::Oid;\nuse sqlx::postgres::{\n    PgAdvisoryLock, PgConnectOptions, PgConnection, PgDatabaseError, PgErrorPosition, PgListener,\n    PgPoolOptions, PgRow, PgSeverity, Postgres, PG_COPY_MAX_DATA_LEN,\n};\nuse sqlx::{Column, Connection, Executor, Row, SqlSafeStr, Statement, TypeInfo};\nuse sqlx_core::sql_str::AssertSqlSafe;\nuse sqlx_core::{bytes::Bytes, error::BoxDynError};\nuse sqlx_test::{new, pool, setup_if_needed};\nuse std::env;\nuse std::pin::{pin, Pin};\nuse std::sync::Arc;\nuse std::time::Duration;\n\n#[sqlx_macros::test]\nasync fn it_connects() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let value = sqlx::query(\"select 1 + 1\")\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(2i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_select_void() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // pg_notify just happens to be a function that returns void\n    let _: () = sqlx::query_scalar(\"select pg_notify('chan', 'message');\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_pings() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.ping().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_pings_after_suspended_query() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    sqlx::raw_sql(\"create temporary table processed_row(val int4 primary key)\")\n        .execute(&mut conn)\n        .await?;\n\n    // This query wants to return 50 rows but we only read the first one.\n    // This will return a `SuspendedPortal` that the driver currently ignores.\n    let _: i32 = sqlx::query_scalar(\n        r#\"\n            insert into processed_row(val)\n            select * from generate_series(1, 50)\n            returning val\n        \"#,\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    // `Sync` closes the current autocommit transaction which presumably includes closing any\n    // suspended portals.\n    conn.ping().await?;\n\n    // Make sure that all the values got inserted even though we only read the first one back.\n    let count: i64 = sqlx::query_scalar(\"select count(*) from processed_row\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 50);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_maths() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let value = sqlx::query(\"select 1 + $1::int\")\n        .bind(5_i32)\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(6i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_inspect_errors() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"select f\").execute(&mut conn).await;\n    let err = res.unwrap_err();\n\n    // can also do [as_database_error] or use `match ..`\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.message(), \"column \\\"f\\\" does not exist\");\n    assert_eq!(err.code().as_deref(), Some(\"42703\"));\n\n    // can also do [downcast_ref]\n    let err: Box<PgDatabaseError> = err.downcast();\n\n    assert_eq!(err.severity(), PgSeverity::Error);\n    assert_eq!(err.message(), \"column \\\"f\\\" does not exist\");\n    assert_eq!(err.code(), \"42703\");\n    assert_eq!(err.position(), Some(PgErrorPosition::Original(8)));\n    assert_eq!(err.routine(), Some(\"errorMissingColumn\"));\n    assert_eq!(err.constraint(), None);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_inspect_constraint_errors() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO products VALUES (1, 'Product 1', 0);\")\n            .execute(&mut conn)\n            .await;\n    let err = res.unwrap_err();\n\n    // can also do [as_database_error] or use `match ..`\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(\n        err.message(),\n        \"new row for relation \\\"products\\\" violates check constraint \\\"products_price_check\\\"\"\n    );\n    assert_eq!(err.code().as_deref(), Some(\"23514\"));\n\n    // can also do [downcast_ref]\n    let err: Box<PgDatabaseError> = err.downcast();\n\n    assert_eq!(err.severity(), PgSeverity::Error);\n    assert_eq!(\n        err.message(),\n        \"new row for relation \\\"products\\\" violates check constraint \\\"products_price_check\\\"\"\n    );\n    assert_eq!(err.code(), \"23514\");\n    assert_eq!(err.position(), None);\n    assert_eq!(err.routine(), Some(\"ExecConstraints\"));\n    assert_eq!(err.constraint(), Some(\"products_price_check\"));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY);\n            \"#,\n        )\n        .await?;\n\n    for index in 1..=10_i32 {\n        let done = sqlx::query(\"INSERT INTO users (id) VALUES ($1)\")\n            .bind(index)\n            .execute(&mut conn)\n            .await?;\n\n        assert_eq!(done.rows_affected(), 1);\n    }\n\n    let sum: i32 = sqlx::query(\"SELECT id FROM users\")\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch(&mut conn)\n        .try_fold(0_i32, |acc, x| async move { Ok(acc + x) })\n        .await?;\n\n    assert_eq!(sum, 55);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_nest_map() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let res = sqlx::query(\"SELECT 5\")\n        .map(|row: PgRow| row.get(0))\n        .map(|int: i32| int.to_string())\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(res, \"5\");\n\n    Ok(())\n}\n\n#[cfg(feature = \"json\")]\n#[sqlx_macros::test]\nasync fn it_describes_and_inserts_json_and_jsonb() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TEMPORARY TABLE json_stuff (obj json, obj2 jsonb);\n            \"#,\n        )\n        .await?;\n\n    let query = \"INSERT INTO json_stuff (obj, obj2) VALUES ($1, $2)\";\n    let _ = conn.describe(query.into_sql_str()).await?;\n\n    let done = sqlx::query(query)\n        .bind(serde_json::json!({ \"a\": \"a\" }))\n        .bind(serde_json::json!({ \"a\": \"a\" }))\n        .execute(&mut conn)\n        .await?;\n\n    assert_eq!(done.rows_affected(), 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_works_with_cache_disabled() -> anyhow::Result<()> {\n    setup_if_needed();\n\n    let mut url = url::Url::parse(&env::var(\"DATABASE_URL\")?)?;\n    url.query_pairs_mut()\n        .append_pair(\"statement-cache-capacity\", \"0\");\n\n    let mut conn = PgConnection::connect(url.as_ref()).await?;\n\n    for index in 1..=10_i32 {\n        let _ = sqlx::query(\"SELECT $1\")\n            .bind(index)\n            .execute(&mut conn)\n            .await?;\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes_with_pool() -> anyhow::Result<()> {\n    let pool = sqlx_test::pool::<Postgres>().await?;\n\n    let rows = pool.fetch_all(\"SELECT 1; SElECT 2\").await?;\n\n    assert_eq!(rows.len(), 2);\n\n    Ok(())\n}\n\n// https://github.com/launchbadge/sqlx/issues/104\n#[sqlx_macros::test]\nasync fn it_can_return_interleaved_nulls_issue_104() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let tuple = sqlx::query(\"SELECT NULL, 10::INT, NULL, 20::INT, NULL, 40::INT, NULL, 80::INT\")\n        .map(|row: PgRow| {\n            (\n                row.get::<Option<i32>, _>(0),\n                row.get::<Option<i32>, _>(1),\n                row.get::<Option<i32>, _>(2),\n                row.get::<Option<i32>, _>(3),\n                row.get::<Option<i32>, _>(4),\n                row.get::<Option<i32>, _>(5),\n                row.get::<Option<i32>, _>(6),\n                row.get::<Option<i32>, _>(7),\n            )\n        })\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(tuple.0, None);\n    assert_eq!(tuple.1, Some(10));\n    assert_eq!(tuple.2, None);\n    assert_eq!(tuple.3, Some(20));\n    assert_eq!(tuple.4, None);\n    assert_eq!(tuple.5, Some(40));\n    assert_eq!(tuple.6, None);\n    assert_eq!(tuple.7, Some(80));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fail_and_recover() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    for i in 0..10 {\n        // make a query that will fail\n        let res = conn\n            .execute(\"INSERT INTO not_found (column) VALUES (10)\")\n            .await;\n\n        assert!(res.is_err());\n\n        // now try and use the connection\n        let val: i32 = conn\n            .fetch_one(AssertSqlSafe(format!(\"SELECT {i}::int4\")))\n            .await?\n            .get(0);\n\n        assert_eq!(val, i);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_fail_and_recover_with_pool() -> anyhow::Result<()> {\n    let pool = sqlx_test::pool::<Postgres>().await?;\n\n    for i in 0..10 {\n        // make a query that will fail\n        let res = pool\n            .execute(\"INSERT INTO not_found (column) VALUES (10)\")\n            .await;\n\n        assert!(res.is_err());\n\n        // now try and use the connection\n        let val: i32 = pool\n            .fetch_one(AssertSqlSafe(format!(\"SELECT {i}::int4\")))\n            .await?\n            .get(0);\n\n        assert_eq!(val, i);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_query_scalar() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let scalar: i32 = sqlx::query_scalar(\"SELECT 42\").fetch_one(&mut conn).await?;\n    assert_eq!(scalar, 42);\n\n    let scalar: Option<i32> = sqlx::query_scalar(\"SELECT 42\").fetch_one(&mut conn).await?;\n    assert_eq!(scalar, Some(42));\n\n    let scalar: Option<i32> = sqlx::query_scalar(\"SELECT NULL\")\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(scalar, None);\n\n    let scalar: Option<i64> = sqlx::query_scalar(\"SELECT 42::bigint\")\n        .fetch_optional(&mut conn)\n        .await?;\n    assert_eq!(scalar, Some(42));\n\n    let scalar: Option<i16> = sqlx::query_scalar(\"\").fetch_optional(&mut conn).await?;\n    assert_eq!(scalar, None);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\n/// This is separate from `it_can_query_scalar` because while implementing it I ran into a\n/// bug which that prevented `Vec<i32>` from compiling but allowed Vec<Option<i32>>.\nasync fn it_can_query_all_scalar() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let scalar: Vec<i32> = sqlx::query_scalar(\"SELECT $1\")\n        .bind(42)\n        .fetch_all(&mut conn)\n        .await?;\n    assert_eq!(scalar, vec![42]);\n\n    let scalar: Vec<Option<i32>> = sqlx::query_scalar(\"SELECT $1 UNION ALL SELECT NULL\")\n        .bind(42)\n        .fetch_all(&mut conn)\n        .await?;\n    assert_eq!(scalar, vec![Some(42), None]);\n\n    Ok(())\n}\n\n#[ignore]\n#[sqlx_macros::test]\nasync fn copy_can_work_with_failed_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // We're using a (local) statement_timeout to simulate a runtime failure, as opposed to\n    // a parse/plan failure.\n    let mut tx = conn.begin().await?;\n    let _ = sqlx::query(\"SELECT pg_catalog.set_config($1, $2, true)\")\n        .bind(\"statement_timeout\")\n        .bind(\"1ms\")\n        .execute(tx.as_mut())\n        .await?;\n\n    let mut copy_out: Pin<\n        Box<dyn Stream<Item = Result<Bytes, sqlx::Error>> + Send>,\n    > = (&mut tx)\n        .copy_out_raw(\"COPY (SELECT nspname FROM pg_catalog.pg_namespace WHERE pg_sleep(0.001) IS NULL) TO STDOUT\")\n        .await?;\n\n    while copy_out.try_next().await.is_ok() {}\n    drop(copy_out);\n\n    tx.rollback().await?;\n\n    // conn should be usable again, as we explicitly rolled back the transaction\n    let got: i32 = sqlx::query_scalar(\"SELECT 1\")\n        .fetch_one(conn.as_mut())\n        .await?;\n    assert_eq!(1, got);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_work_with_failed_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // We're using a (local) statement_timeout to simulate a runtime failure, as opposed to\n    // a parse/plan failure.\n    let mut tx = conn.begin().await?;\n    let _ = sqlx::query(\"SELECT pg_catalog.set_config($1, $2, true)\")\n        .bind(\"statement_timeout\")\n        .bind(\"1ms\")\n        .execute(tx.as_mut())\n        .await?;\n\n    assert!(sqlx::query(\"SELECT 1 WHERE pg_sleep(0.30) IS NULL\")\n        .fetch_one(tx.as_mut())\n        .await\n        .is_err());\n    tx.rollback().await?;\n\n    // conn should be usable again, as we explicitly rolled back the transaction\n    let got: i32 = sqlx::query_scalar(\"SELECT 1\")\n        .fetch_one(conn.as_mut())\n        .await?;\n    assert_eq!(1, got);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_work_with_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\"CREATE TABLE IF NOT EXISTS _sqlx_users_1922 (id INTEGER PRIMARY KEY)\")\n        .await?;\n\n    conn.execute(\"TRUNCATE _sqlx_users_1922\").await?;\n\n    // begin .. rollback\n\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO _sqlx_users_1922 (id) VALUES ($1)\")\n        .bind(10_i32)\n        .execute(&mut *tx)\n        .await?;\n\n    tx.rollback().await?;\n\n    let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_1922\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 0);\n\n    // begin .. commit\n\n    let mut tx = conn.begin().await?;\n\n    sqlx::query(\"INSERT INTO _sqlx_users_1922 (id) VALUES ($1)\")\n        .bind(10_i32)\n        .execute(&mut *tx)\n        .await?;\n\n    tx.commit().await?;\n\n    let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_1922\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    // begin .. (drop)\n\n    {\n        let mut tx = conn.begin().await?;\n\n        sqlx::query(\"INSERT INTO _sqlx_users_1922 (id) VALUES ($1)\")\n            .bind(20_i32)\n            .execute(&mut *tx)\n            .await?;\n    }\n\n    conn = new::<Postgres>().await?;\n\n    let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_1922\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_work_with_nested_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    assert!(!conn.is_in_transaction());\n\n    conn.execute(\"CREATE TABLE IF NOT EXISTS _sqlx_users_2523 (id INTEGER PRIMARY KEY)\")\n        .await?;\n\n    conn.execute(\"TRUNCATE _sqlx_users_2523\").await?;\n\n    // begin\n    let mut tx = conn.begin().await?; // transaction\n    assert!(tx.is_in_transaction());\n\n    // insert a user\n    sqlx::query(\"INSERT INTO _sqlx_users_2523 (id) VALUES ($1)\")\n        .bind(50_i32)\n        .execute(&mut *tx)\n        .await?;\n\n    // begin once more\n    let mut tx2 = tx.begin().await?; // savepoint\n    assert!(tx2.is_in_transaction());\n\n    // insert another user\n    sqlx::query(\"INSERT INTO _sqlx_users_2523 (id) VALUES ($1)\")\n        .bind(10_i32)\n        .execute(&mut *tx2)\n        .await?;\n\n    // never mind, rollback\n    tx2.rollback().await?; // roll that one back\n    assert!(tx.is_in_transaction());\n\n    // did we really?\n    let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_2523\")\n        .fetch_one(&mut *tx)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    // actually, commit\n    tx.commit().await?;\n    assert!(!conn.is_in_transaction());\n\n    // did we really?\n    let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_2523\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(count, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_drop_multiple_transactions() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\"CREATE TABLE IF NOT EXISTS _sqlx_users_3952 (id INTEGER PRIMARY KEY)\")\n        .await?;\n\n    conn.execute(\"TRUNCATE _sqlx_users_3952\").await?;\n\n    // begin .. (drop)\n\n    // run 2 times to see what happens if we drop transactions repeatedly\n    for _ in 0..2 {\n        {\n            let mut tx = conn.begin().await?;\n\n            // do actually something before dropping\n            let _user = sqlx::query(\"INSERT INTO _sqlx_users_3952 (id) VALUES ($1) RETURNING id\")\n                .bind(20_i32)\n                .fetch_one(&mut *tx)\n                .await?;\n        }\n\n        let (count,): (i64,) = sqlx::query_as(\"SELECT COUNT(*) FROM _sqlx_users_3952\")\n            .fetch_one(&mut conn)\n            .await?;\n\n        assert_eq!(count, 0);\n    }\n\n    Ok(())\n}\n\n// run with `cargo test --features postgres -- --ignored --nocapture pool_smoke_test`\n#[ignore]\n#[sqlx_macros::test]\nasync fn pool_smoke_test() -> anyhow::Result<()> {\n    use futures_util::{task::Poll, Future};\n\n    eprintln!(\"starting pool\");\n\n    let pool = PgPoolOptions::new()\n        .acquire_timeout(Duration::from_secs(5))\n        .min_connections(1)\n        .max_connections(1)\n        .connect(&dotenvy::var(\"DATABASE_URL\")?)\n        .await?;\n\n    // spin up more tasks than connections available, and ensure we don't deadlock\n    for i in 0..200 {\n        let pool = pool.clone();\n        sqlx_core::rt::spawn(async move {\n            for j in 0.. {\n                if let Err(e) = sqlx::query(\"select 1 + 1\").execute(&pool).await {\n                    // normal error at termination of the test\n                    if matches!(e, sqlx::Error::PoolClosed) {\n                        eprintln!(\"pool task {i} exiting normally after {j} iterations\");\n                    } else {\n                        eprintln!(\"pool task {i} dying due to {e} after {j} iterations\");\n                    }\n                    break;\n                }\n\n                // shouldn't be necessary if the pool is fair\n                // sqlx_core::rt::yield_now().await;\n            }\n        });\n    }\n\n    // spawn a bunch of tasks that attempt to acquire but give up to ensure correct handling\n    // of cancellations\n    for _ in 0..50 {\n        let pool = pool.clone();\n        sqlx_core::rt::spawn(async move {\n            while !pool.is_closed() {\n                let mut acquire = pin!(pool.acquire());\n\n                // poll the acquire future once to put the waiter in the queue\n                std::future::poll_fn(move |cx| {\n                    let _ = acquire.as_mut().poll(cx);\n                    Poll::Ready(())\n                })\n                .await;\n\n                // this one is necessary since this is a hot loop,\n                // otherwise this task will never be descheduled\n                sqlx_core::rt::yield_now().await;\n            }\n        });\n    }\n\n    eprintln!(\"sleeping for 30 seconds\");\n\n    sqlx_core::rt::sleep(Duration::from_secs(30)).await;\n\n    // assert_eq!(pool.size(), 10);\n\n    eprintln!(\"closing pool\");\n\n    sqlx_core::rt::timeout(Duration::from_secs(30), pool.close()).await?;\n\n    eprintln!(\"pool closed successfully\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_invalid_query() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\"definitely not a correct query\")\n        .await\n        .unwrap_err();\n\n    let mut s = conn.fetch(\"select 1\");\n    let row = s.try_next().await?.unwrap();\n\n    assert_eq!(row.get::<i32, _>(0), 1i32);\n\n    Ok(())\n}\n\n/// Tests the edge case of executing a completely empty query string.\n///\n/// This gets flagged as an `EmptyQueryResponse` in Postgres. We\n/// catch this and just return no rows.\n#[sqlx_macros::test]\nasync fn test_empty_query() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let done = conn.execute(\"\").await?;\n\n    assert_eq!(done.rows_affected(), 0);\n\n    Ok(())\n}\n\n/// Test a simple select expression. This should return the row.\n#[sqlx_macros::test]\nasync fn test_select_expression() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let mut s = conn.fetch(\"SELECT 5\");\n    let row = s.try_next().await?.unwrap();\n\n    assert!(5i32 == row.try_get::<i32, _>(0)?);\n\n    Ok(())\n}\n\n/// Test that we can interleave reads and writes to the database\n/// in one simple query. Using the `Cursor` API we should be\n/// able to fetch from both queries in sequence.\n#[sqlx_macros::test]\nasync fn test_multi_read_write() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let mut s = conn.fetch(\n        \"\nCREATE TABLE IF NOT EXISTS _sqlx_test_postgres_5112 (\n    id BIGSERIAL PRIMARY KEY,\n    text TEXT NOT NULL\n);\n\nSELECT 'Hello World' as _1;\n\nINSERT INTO _sqlx_test_postgres_5112 (text) VALUES ('this is a test');\n\nSELECT id, text FROM _sqlx_test_postgres_5112;\n    \",\n    );\n\n    let row = s.try_next().await?.unwrap();\n\n    assert!(\"Hello World\" == row.try_get::<&str, _>(\"_1\")?);\n\n    let row = s.try_next().await?.unwrap();\n\n    let id: i64 = row.try_get(\"id\")?;\n    let text: &str = row.try_get(\"text\")?;\n\n    assert_eq!(1_i64, id);\n    assert_eq!(\"this is a test\", text);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_caches_statements() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT $1 AS val\")\n            .bind(Oid(i))\n            .persistent(true)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: Oid = row.get(\"val\");\n\n        assert_eq!(Oid(i), val);\n    }\n\n    assert_eq!(1, conn.cached_statements_size());\n    conn.clear_cached_statements().await?;\n    assert_eq!(0, conn.cached_statements_size());\n\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT $1 AS val\")\n            .bind(Oid(i))\n            .persistent(false)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: Oid = row.get(\"val\");\n\n        assert_eq!(Oid(i), val);\n    }\n\n    assert_eq!(0, conn.cached_statements_size());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_closes_statement_from_cache_issue_470() -> anyhow::Result<()> {\n    sqlx_test::setup_if_needed();\n\n    let mut options: PgConnectOptions = env::var(\"DATABASE_URL\")?.parse().unwrap();\n\n    // a capacity of 1 means that before each statement (after the first)\n    // we will close the previous statement\n    options = options.statement_cache_capacity(1);\n\n    let mut conn = PgConnection::connect_with(&options).await?;\n\n    for i in 0..5 {\n        let row = sqlx::query(AssertSqlSafe(format!(\"SELECT {i}::int4 AS val\")))\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: i32 = row.get(\"val\");\n\n        assert_eq!(i, val);\n    }\n\n    assert_eq!(1, conn.cached_statements_size());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_closes_statements_when_not_persistent_issue_3850() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let _row = sqlx::query(\"SELECT $1 AS val\")\n        .bind(Oid(1))\n        .persistent(false)\n        .fetch_one(&mut conn)\n        .await?;\n\n    let row = sqlx::query(\"SELECT count(*) AS num_prepared_statements FROM pg_prepared_statements\")\n        .persistent(false)\n        .fetch_one(&mut conn)\n        .await?;\n\n    let n: i64 = row.get(\"num_prepared_statements\");\n    assert_eq!(0, n, \"no prepared statements should be open\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_sets_application_name() -> anyhow::Result<()> {\n    sqlx_test::setup_if_needed();\n\n    let mut options: PgConnectOptions = env::var(\"DATABASE_URL\")?.parse().unwrap();\n    options = options.application_name(\"some-name\");\n\n    let mut conn = PgConnection::connect_with(&options).await?;\n\n    let row = sqlx::query(\"select current_setting('application_name') as app_name\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    let val: String = row.get(\"app_name\");\n\n    assert_eq!(\"some-name\", &val);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_handle_parameter_status_message_issue_484() -> anyhow::Result<()> {\n    new::<Postgres>().await?.execute(\"SET NAMES 'UTF8'\").await?;\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_prepare_then_execute() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    let mut tx = conn.begin().await?;\n\n    let tweet_id: i64 =\n        sqlx::query_scalar(\"INSERT INTO tweet ( text ) VALUES ( 'Hello, World' ) RETURNING id\")\n            .fetch_one(&mut *tx)\n            .await?;\n\n    let statement = tx\n        .prepare(\"SELECT * FROM tweet WHERE id = $1\".into_sql_str())\n        .await?;\n\n    assert_eq!(statement.column(0).name(), \"id\");\n    assert_eq!(statement.column(1).name(), \"created_at\");\n    assert_eq!(statement.column(2).name(), \"text\");\n    assert_eq!(statement.column(3).name(), \"owner_id\");\n\n    assert_eq!(statement.column(0).type_info().name(), \"INT8\");\n    assert_eq!(statement.column(1).type_info().name(), \"TIMESTAMPTZ\");\n    assert_eq!(statement.column(2).type_info().name(), \"TEXT\");\n    assert_eq!(statement.column(3).type_info().name(), \"INT8\");\n\n    let row = statement.query().bind(tweet_id).fetch_one(&mut *tx).await?;\n    let tweet_text: &str = row.try_get(\"text\")?;\n\n    assert_eq!(tweet_text, \"Hello, World\");\n\n    Ok(())\n}\n\n// repro is more reliable with the basic scheduler used by `#[tokio::test]`\n#[cfg(feature = \"_rt-tokio\")]\n#[tokio::test]\nasync fn test_issue_622() -> anyhow::Result<()> {\n    use std::time::Instant;\n\n    setup_if_needed();\n\n    let pool = PgPoolOptions::new()\n        .max_connections(1) // also fails with higher counts, e.g. 5\n        .connect(&std::env::var(\"DATABASE_URL\").unwrap())\n        .await?;\n\n    println!(\"pool state: {pool:?}\");\n\n    let mut handles = vec![];\n\n    // given repro spawned 100 tasks but I found it reliably reproduced with 3\n    for i in 0..3 {\n        let pool = pool.clone();\n\n        handles.push(sqlx_core::rt::spawn(async move {\n            {\n                let mut conn = pool.acquire().await.unwrap();\n\n                let _ = sqlx::query(\"SELECT 1\").fetch_one(&mut *conn).await.unwrap();\n\n                // conn gets dropped here and should be returned to the pool\n            }\n\n            // (do some other work here without holding on to a connection)\n            // this actually fixes the issue, depending on the timeout used\n            // sqlx_core::rt::sleep(Duration::from_millis(500)).await;\n\n            {\n                let start = Instant::now();\n                match pool.acquire().await {\n                    Ok(conn) => {\n                        println!(\"{} acquire took {:?}\", i, start.elapsed());\n                        drop(conn);\n                    }\n                    Err(e) => panic!(\"{i} acquire returned error: {e} pool state: {pool:?}\"),\n                }\n            }\n\n            Result::<(), anyhow::Error>::Ok(())\n        }));\n    }\n\n    futures_util::future::try_join_all(handles).await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_describe_outer_join_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    // test nullability inference for various joins\n\n    // inner join, nullability should not be overridden\n    // language=PostgreSQL\n    let describe = conn\n        .describe(\n            \"select tweet.id\n    from tweet\n    inner join products on products.name = tweet.text\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(describe.nullable(0), Some(false));\n\n    // language=PostgreSQL\n    let describe = conn\n        .describe(\n            \"select tweet.id\nfrom (values (null)) vals(val)\n         left join tweet on false\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    // tweet.id is marked NOT NULL but it's brought in from a left-join here\n    // which should make it nullable\n    assert_eq!(describe.nullable(0), Some(true));\n\n    // make sure we don't mis-infer for the outer half of the join\n    // language=PostgreSQL\n    let describe = conn\n        .describe(\n            \"select tweet1.id, tweet2.id\n    from tweet tweet1\n    left join tweet tweet2 on false\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(describe.nullable(0), Some(false));\n    assert_eq!(describe.nullable(1), Some(true));\n\n    // right join, nullability should be inverted\n    // language=PostgreSQL\n    let describe = conn\n        .describe(\n            \"select tweet1.id, tweet2.id\n    from tweet tweet1\n    right join tweet tweet2 on false\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(describe.nullable(0), Some(true));\n    assert_eq!(describe.nullable(1), Some(false));\n\n    // full outer join, both tables are nullable\n    // language=PostgreSQL\n    let describe = conn\n        .describe(\n            \"select tweet1.id, tweet2.id\n    from tweet tweet1\n    full join tweet tweet2 on false\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(describe.nullable(0), Some(true));\n    assert_eq!(describe.nullable(1), Some(true));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_listener_cleanup() -> anyhow::Result<()> {\n    use sqlx_core::rt::timeout;\n\n    use sqlx::pool::PoolOptions;\n    use sqlx::postgres::PgListener;\n\n    // Create a connection on which to send notifications\n    let mut notify_conn = new::<Postgres>().await?;\n\n    // Create a pool with exactly one connection so we can\n    // deterministically test the cleanup.\n    let pool = PoolOptions::<Postgres>::new()\n        .min_connections(1)\n        .max_connections(1)\n        .test_before_acquire(true)\n        .connect(&env::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let mut listener = PgListener::connect_with(&pool).await?;\n    listener.listen(\"test_channel\").await?;\n\n    // Checks for a notification on the test channel\n    async fn try_recv(listener: &mut PgListener) -> anyhow::Result<bool> {\n        match timeout(Duration::from_millis(100), listener.recv()).await {\n            Ok(res) => {\n                res?;\n                Ok(true)\n            }\n            Err(_) => Ok(false),\n        }\n    }\n\n    // Check no notification is received before one is sent\n    assert!(!try_recv(&mut listener).await?, \"Notification not sent\");\n\n    // Check notification is sent and received\n    notify_conn.execute(\"NOTIFY test_channel\").await?;\n    assert!(\n        try_recv(&mut listener).await?,\n        \"Notification sent and received\"\n    );\n    assert!(\n        !try_recv(&mut listener).await?,\n        \"Notification is not duplicated\"\n    );\n\n    // Test that cleanup stops listening on the channel\n    drop(listener);\n    let mut listener = PgListener::connect_with(&pool).await?;\n\n    // Check notification is sent but not received\n    notify_conn.execute(\"NOTIFY test_channel\").await?;\n    assert!(\n        !try_recv(&mut listener).await?,\n        \"Notification is not received on fresh listener\"\n    );\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_listener_try_recv_buffered() -> anyhow::Result<()> {\n    use sqlx_core::rt::timeout;\n\n    use sqlx::pool::PoolOptions;\n    use sqlx::postgres::PgListener;\n\n    // Create a connection on which to send notifications\n    let mut notify_conn = new::<Postgres>().await?;\n\n    let pool = PoolOptions::<Postgres>::new()\n        .min_connections(1)\n        .max_connections(1)\n        .test_before_acquire(true)\n        .connect(&env::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let mut listener = PgListener::connect_with(&pool).await?;\n    listener.listen(\"test_channel2\").await?;\n\n    // Checks for a notification on the test channel\n    async fn try_recv(listener: &mut PgListener) -> anyhow::Result<bool> {\n        match timeout(Duration::from_millis(100), listener.recv()).await {\n            Ok(res) => {\n                res?;\n                Ok(true)\n            }\n            Err(_) => Ok(false),\n        }\n    }\n\n    // Check no notification is buffered, since we haven't sent one.\n    assert!(listener.next_buffered().is_none());\n\n    // Send five notifications transactionally, so they all arrive at once.\n    {\n        let mut txn = notify_conn.begin().await?;\n        for i in 0..5 {\n            txn.execute(AssertSqlSafe(format!(\n                \"NOTIFY test_channel2, 'payload {i}'\"\n            )))\n            .await?;\n        }\n        txn.commit().await?;\n    }\n\n    // Still no notifications buffered, since we haven't awaited the listener yet.\n    assert!(listener.next_buffered().is_none());\n\n    // Activate connection.\n    sqlx::query!(\"SELECT 1 AS one\")\n        .fetch_all(&mut listener)\n        .await?;\n\n    // The next five notifications should now be buffered.\n    for i in 0..5 {\n        assert!(\n            listener.next_buffered().is_some(),\n            \"Notification {i} was not buffered\"\n        );\n    }\n\n    // Should be no more.\n    assert!(listener.next_buffered().is_none());\n\n    // Even if we wait.\n    assert!(!try_recv(&mut listener).await?, \"Notification received\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_pg_listener_allows_pool_to_close() -> anyhow::Result<()> {\n    let pool = pool::<Postgres>().await?;\n\n    // acquires and holds a connection which would normally prevent the pool from closing\n    let mut listener = PgListener::connect_with(&pool).await?;\n\n    sqlx_core::rt::spawn(async move {\n        listener.recv().await.unwrap();\n    });\n\n    // would previously hang forever since `PgListener` had no way to know the pool wanted to close\n    pool.close().await;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_pg_listener_implements_acquire() -> anyhow::Result<()> {\n    use sqlx::Acquire;\n\n    let pool = pool::<Postgres>().await?;\n\n    let mut listener = PgListener::connect_with(&pool).await?;\n    listener\n        .listen(\"test_pg_listener_implements_acquire\")\n        .await?;\n\n    // Start a transaction on the underlying connection\n    let mut txn = listener.begin().await?;\n\n    // This will reuse the same connection, so this connection should be listening to the channel\n    let channels: Vec<String> = sqlx::query_scalar(\"SELECT pg_listening_channels()\")\n        .fetch_all(&mut *txn)\n        .await?;\n\n    assert_eq!(channels, vec![\"test_pg_listener_implements_acquire\"]);\n\n    // Send a notification\n    sqlx::query(\"NOTIFY test_pg_listener_implements_acquire, 'hello'\")\n        .execute(&mut *txn)\n        .await?;\n\n    txn.commit().await?;\n\n    // And now we can receive the notification we sent in the transaction\n    let notification = listener.recv().await?;\n    assert_eq!(\n        notification.channel(),\n        \"test_pg_listener_implements_acquire\"\n    );\n    assert_eq!(notification.payload(), \"hello\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_supports_domain_types_in_composite_domain_types() -> anyhow::Result<()> {\n    // Only supported in Postgres 11+\n    let mut conn = new::<Postgres>().await?;\n    if matches!(conn.server_version_num(), Some(version) if version < 110000) {\n        return Ok(());\n    }\n\n    conn.execute(\n        r#\"\nDROP TABLE IF EXISTS heating_bills;\nDROP DOMAIN IF EXISTS winter_year_month;\nDROP TYPE IF EXISTS year_month;\nDROP DOMAIN IF EXISTS month_id;\n\nCREATE DOMAIN month_id AS INT2 CHECK (1 <= value AND value <= 12);\nCREATE TYPE year_month AS (year INT4, month month_id);\nCREATE DOMAIN winter_year_month AS year_month CHECK ((value).month <= 3);\nCREATE TABLE heating_bills (\n  month winter_year_month NOT NULL PRIMARY KEY,\n  cost INT4 NOT NULL\n);\n    \"#,\n    )\n    .await?;\n\n    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct MonthId(i16);\n\n    impl sqlx::Type<Postgres> for MonthId {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            sqlx::postgres::PgTypeInfo::with_name(\"month_id\")\n        }\n\n        fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {\n            *ty == Self::type_info()\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for MonthId {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            Ok(Self(<i16 as sqlx::Decode<Postgres>>::decode(value)?))\n        }\n    }\n\n    impl<'q> sqlx::Encode<'q, Postgres> for MonthId {\n        fn encode_by_ref(\n            &self,\n            buf: &mut sqlx::postgres::PgArgumentBuffer,\n        ) -> Result<sqlx::encode::IsNull, BoxDynError> {\n            <i16 as sqlx::Encode<Postgres>>::encode(self.0, buf)\n        }\n    }\n\n    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct WinterYearMonth {\n        year: i32,\n        month: MonthId,\n    }\n\n    impl sqlx::Type<Postgres> for WinterYearMonth {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            sqlx::postgres::PgTypeInfo::with_name(\"winter_year_month\")\n        }\n\n        fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {\n            *ty == Self::type_info()\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for WinterYearMonth {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            let mut decoder = sqlx::postgres::types::PgRecordDecoder::new(value)?;\n\n            let year = decoder.try_decode::<i32>()?;\n            let month = decoder.try_decode::<MonthId>()?;\n\n            Ok(Self { year, month })\n        }\n    }\n\n    impl<'q> sqlx::Encode<'q, Postgres> for WinterYearMonth {\n        fn encode_by_ref(\n            &self,\n            buf: &mut sqlx::postgres::PgArgumentBuffer,\n        ) -> Result<sqlx::encode::IsNull, sqlx::error::BoxDynError> {\n            let mut encoder = sqlx::postgres::types::PgRecordEncoder::new(buf);\n            encoder.encode(self.year)?;\n            encoder.encode(self.month)?;\n            encoder.finish();\n            Ok(sqlx::encode::IsNull::No)\n        }\n    }\n    let mut conn = new::<Postgres>().await?;\n\n    let result = sqlx::query(\"DELETE FROM heating_bills;\")\n        .execute(&mut conn)\n        .await;\n\n    let result = result.unwrap();\n    assert_eq!(result.rows_affected(), 0);\n\n    let result =\n        sqlx::query(\"INSERT INTO heating_bills(month, cost) VALUES($1::winter_year_month, 100);\")\n            .bind(WinterYearMonth {\n                year: 2021,\n                month: MonthId(1),\n            })\n            .execute(&mut conn)\n            .await;\n\n    let result = result.unwrap();\n    assert_eq!(result.rows_affected(), 1);\n\n    let result = sqlx::query(\"DELETE FROM heating_bills;\")\n        .execute(&mut conn)\n        .await;\n\n    let result = result.unwrap();\n    assert_eq!(result.rows_affected(), 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_resolves_custom_type_in_array() -> anyhow::Result<()> {\n    // Only supported in Postgres 11+\n    let mut conn = new::<Postgres>().await?;\n    if matches!(conn.server_version_num(), Some(version) if version < 110000) {\n        return Ok(());\n    }\n\n    // language=PostgreSQL\n    conn.execute(\n        r#\"\nDROP TABLE IF EXISTS pets;\nDROP TYPE IF EXISTS pet_name_and_race;\n\nCREATE TYPE pet_name_and_race AS (\n  name TEXT,\n  race TEXT\n);\nCREATE TABLE pets (\n  owner TEXT NOT NULL,\n  name TEXT NOT NULL,\n  race TEXT NOT NULL,\n  PRIMARY KEY (owner, name)\n);\nINSERT INTO pets(owner, name, race)\nVALUES\n  ('Alice', 'Foo', 'cat');\nINSERT INTO pets(owner, name, race)\nVALUES\n  ('Alice', 'Bar', 'dog');\n    \"#,\n    )\n    .await?;\n\n    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct PetNameAndRace {\n        name: String,\n        race: String,\n    }\n\n    impl sqlx::Type<Postgres> for PetNameAndRace {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            sqlx::postgres::PgTypeInfo::with_name(\"pet_name_and_race\")\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for PetNameAndRace {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            let mut decoder = sqlx::postgres::types::PgRecordDecoder::new(value)?;\n            let name = decoder.try_decode::<String>()?;\n            let race = decoder.try_decode::<String>()?;\n            Ok(Self { name, race })\n        }\n    }\n\n    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct PetNameAndRaceArray(Vec<PetNameAndRace>);\n\n    impl sqlx::Type<Postgres> for PetNameAndRaceArray {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            // Array type name is the name of the element type prefixed with `_`\n            sqlx::postgres::PgTypeInfo::with_name(\"_pet_name_and_race\")\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for PetNameAndRaceArray {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            Ok(Self(Vec::<PetNameAndRace>::decode(value)?))\n        }\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let row = sqlx::query(\"select owner, array_agg(row(name, race)::pet_name_and_race) as pets from pets group by owner\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    let pets: PetNameAndRaceArray = row.get(\"pets\");\n\n    assert_eq!(pets.0.len(), 2);\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_resolves_custom_types_in_anonymous_records() -> anyhow::Result<()> {\n    use sqlx_core::error::Error;\n    // This request involves nested records and array types.\n\n    // Only supported in Postgres 11+\n    let mut conn = new::<Postgres>().await?;\n    if matches!(conn.server_version_num(), Some(version) if version < 110000) {\n        return Ok(());\n    }\n\n    // language=PostgreSQL\n    conn.execute(\n        r#\"\nDROP TABLE IF EXISTS repo_users;\nDROP TABLE IF EXISTS repositories;\nDROP TABLE IF EXISTS repo_memberships;\nDROP TYPE IF EXISTS repo_member;\n\nCREATE TABLE repo_users (\n  user_id INT4 NOT NULL,\n  username TEXT NOT NULL,\n  PRIMARY KEY (user_id)\n);\nCREATE TABLE repositories (\n  repo_id INT4 NOT NULL,\n  repo_name TEXT NOT NULL,\n  PRIMARY KEY (repo_id)\n);\nCREATE TABLE repo_memberships (\n  repo_id INT4 NOT NULL,\n  user_id INT4 NOT NULL,\n  permission TEXT NOT NULL,\n  PRIMARY KEY (repo_id, user_id)\n);\nCREATE TYPE repo_member AS (\n  user_id INT4,\n  permission TEXT\n);\nINSERT INTO repo_users(user_id, username)\nVALUES\n  (101, 'alice'),\n  (102, 'bob'),\n  (103, 'charlie');\nINSERT INTO repositories(repo_id, repo_name)\nVALUES\n  (201, 'rust'),\n  (202, 'sqlx'),\n  (203, 'hello-world');\nINSERT INTO repo_memberships(repo_id, user_id, permission)\nVALUES\n  (201, 101, 'admin'),\n  (201, 102, 'write'),\n  (201, 103, 'read'),\n  (202, 102, 'admin');\n\"#,\n    )\n    .await?;\n\n    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct RepoMember {\n        user_id: i32,\n        permission: String,\n    }\n\n    impl sqlx::Type<Postgres> for RepoMember {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            sqlx::postgres::PgTypeInfo::with_name(\"repo_member\")\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for RepoMember {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            let mut decoder = sqlx::postgres::types::PgRecordDecoder::new(value)?;\n            let user_id = decoder.try_decode::<i32>()?;\n            let permission = decoder.try_decode::<String>()?;\n            Ok(Self {\n                user_id,\n                permission,\n            })\n        }\n    }\n\n    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct RepoMemberArray(Vec<RepoMember>);\n\n    impl sqlx::Type<Postgres> for RepoMemberArray {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            // Array type name is the name of the element type prefixed with `_`\n            sqlx::postgres::PgTypeInfo::with_name(\"_repo_member\")\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for RepoMemberArray {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            Ok(Self(Vec::<RepoMember>::decode(value)?))\n        }\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    #[derive(Debug, sqlx::FromRow)]\n    #[allow(dead_code)] // We don't actually read these fields.\n    struct Row {\n        count: i64,\n        items: Vec<(i32, String, RepoMemberArray)>,\n    }\n    // language=PostgreSQL\n    let row: Result<Row, Error> = sqlx::query_as::<_, Row>(\n        r\"\n        WITH\n          members_by_repo AS (\n            SELECT repo_id,\n              ARRAY_AGG(ROW (user_id, permission)::repo_member) AS members\n            FROM repo_memberships\n            GROUP BY repo_id\n          ),\n          repos AS (\n            SELECT repo_id, repo_name, COALESCE(members, '{}') AS members\n            FROM repositories\n              LEFT OUTER JOIN members_by_repo USING (repo_id)\n            ORDER BY repo_id\n          ),\n          repo_array AS (\n            SELECT COALESCE(ARRAY_AGG(repos.*), '{}') AS items\n            FROM repos\n          ),\n          repo_count AS (\n            SELECT COUNT(*) AS count\n            FROM repos\n          )\n        SELECT count, items\n        FROM repo_count, repo_array\n        ;\n    \",\n    )\n    .fetch_one(&mut conn)\n    .await;\n\n    // This test currently tests mitigations for `#1672` (use regular errors\n    // instead of panics). Once we fully support custom types, it should be\n    // updated accordingly.\n    match row {\n        Ok(_) => panic!(\"full support for custom types is not implemented yet\"),\n        Err(e) => assert!(e\n            .to_string()\n            .contains(\"custom types in records are not fully supported yet\")),\n    }\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn custom_type_resolution_respects_search_path() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\n        r#\"\nDROP TYPE IF EXISTS some_enum_type;\nDROP SCHEMA IF EXISTS another CASCADE;\n\nCREATE SCHEMA another;\nCREATE TYPE some_enum_type AS ENUM ('a', 'b', 'c');\nCREATE TYPE another.some_enum_type AS ENUM ('d', 'e', 'f');\n    \"#,\n    )\n    .await?;\n\n    #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]\n    struct SomeEnumType(String);\n\n    impl sqlx::Type<Postgres> for SomeEnumType {\n        fn type_info() -> sqlx::postgres::PgTypeInfo {\n            sqlx::postgres::PgTypeInfo::with_name(\"some_enum_type\")\n        }\n\n        fn compatible(ty: &sqlx::postgres::PgTypeInfo) -> bool {\n            *ty == Self::type_info()\n        }\n    }\n\n    impl<'r> sqlx::Decode<'r, Postgres> for SomeEnumType {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            Ok(Self(<String as sqlx::Decode<Postgres>>::decode(value)?))\n        }\n    }\n\n    impl<'q> sqlx::Encode<'q, Postgres> for SomeEnumType {\n        fn encode_by_ref(\n            &self,\n            buf: &mut sqlx::postgres::PgArgumentBuffer,\n        ) -> Result<sqlx::encode::IsNull, BoxDynError> {\n            <String as sqlx::Encode<Postgres>>::encode_by_ref(&self.0, buf)\n        }\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    sqlx::query(\"set search_path = 'another'\")\n        .execute(&mut conn)\n        .await?;\n\n    let result = sqlx::query(\"SELECT 1 WHERE $1::some_enum_type = 'd'::some_enum_type;\")\n        .bind(SomeEnumType(\"d\".into()))\n        .fetch_all(&mut conn)\n        .await;\n\n    let result = result.unwrap();\n    assert_eq!(result.len(), 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_pg_server_num() -> anyhow::Result<()> {\n    let conn = new::<Postgres>().await?;\n\n    assert!(conn.server_version_num().is_some());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_copy_in() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    conn.execute(\n        r#\"\n        CREATE TEMPORARY TABLE users (id INTEGER NOT NULL);\n    \"#,\n    )\n    .await?;\n\n    let mut copy = conn\n        .copy_in_raw(\n            r#\"\n        COPY users (id) FROM STDIN WITH (FORMAT CSV, HEADER);\n    \"#,\n        )\n        .await?;\n\n    copy.send(\"id\\n1\\n2\\n\".as_bytes()).await?;\n    let rows = copy.finish().await?;\n    assert_eq!(rows, 2);\n\n    // conn is safe for reuse\n    let value = sqlx::query(\"select 1 + 1\")\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(2i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_abort_copy_in() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    conn.execute(\n        r#\"\n        CREATE TEMPORARY TABLE users (id INTEGER NOT NULL);\n    \"#,\n    )\n    .await?;\n\n    let copy = conn\n        .copy_in_raw(\n            r#\"\n        COPY users (id) FROM STDIN WITH (FORMAT CSV, HEADER);\n    \"#,\n        )\n        .await?;\n\n    copy.abort(\"this is only a test\").await?;\n\n    // conn is safe for reuse\n    let value = sqlx::query(\"select 1 + 1\")\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(2i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_copy_out() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    {\n        let mut copy = conn\n            .copy_out_raw(\n                \"\n            COPY (SELECT generate_series(1, 2) AS id) TO STDOUT WITH (FORMAT CSV, HEADER);\n        \",\n            )\n            .await?;\n\n        assert_eq!(copy.next().await.unwrap().unwrap(), \"id\\n\");\n        assert_eq!(copy.next().await.unwrap().unwrap(), \"1\\n\");\n        assert_eq!(copy.next().await.unwrap().unwrap(), \"2\\n\");\n        if copy.next().await.is_some() {\n            anyhow::bail!(\"Unexpected data from COPY\");\n        }\n    }\n\n    // conn is safe for reuse\n    let value = sqlx::query(\"select 1 + 1\")\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(2i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_encodes_custom_array_issue_1504() -> anyhow::Result<()> {\n    use sqlx::encode::IsNull;\n    use sqlx::postgres::{PgArgumentBuffer, PgTypeInfo};\n    use sqlx::{Decode, Encode, Type, ValueRef};\n\n    #[derive(Debug, PartialEq)]\n    enum Value {\n        String(String),\n        Number(i32),\n        Array(Vec<Value>),\n    }\n\n    impl<'r> Decode<'r, Postgres> for Value {\n        fn decode(\n            value: sqlx::postgres::PgValueRef<'r>,\n        ) -> std::result::Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n            let typ = value.type_info().into_owned();\n\n            if typ == PgTypeInfo::with_name(\"text\") {\n                let s = <String as Decode<'_, Postgres>>::decode(value)?;\n\n                Ok(Self::String(s))\n            } else if typ == PgTypeInfo::with_name(\"int4\") {\n                let n = <i32 as Decode<'_, Postgres>>::decode(value)?;\n\n                Ok(Self::Number(n))\n            } else if typ == PgTypeInfo::with_name(\"_text\") {\n                let arr = Vec::<String>::decode(value)?;\n                let v = arr.into_iter().map(|s| Value::String(s)).collect();\n\n                Ok(Self::Array(v))\n            } else if typ == PgTypeInfo::with_name(\"_int4\") {\n                let arr = Vec::<i32>::decode(value)?;\n                let v = arr.into_iter().map(|n| Value::Number(n)).collect();\n\n                Ok(Self::Array(v))\n            } else {\n                Err(\"unknown type\".into())\n            }\n        }\n    }\n\n    impl Encode<'_, Postgres> for Value {\n        fn produces(&self) -> Option<PgTypeInfo> {\n            match self {\n                Self::Array(a) => {\n                    if a.len() < 1 {\n                        return Some(PgTypeInfo::with_name(\"_text\"));\n                    }\n\n                    match a[0] {\n                        Self::String(_) => Some(PgTypeInfo::with_name(\"_text\")),\n                        Self::Number(_) => Some(PgTypeInfo::with_name(\"_int4\")),\n                        Self::Array(_) => None,\n                    }\n                }\n                Self::String(_) => Some(PgTypeInfo::with_name(\"text\")),\n                Self::Number(_) => Some(PgTypeInfo::with_name(\"int4\")),\n            }\n        }\n\n        fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> Result<IsNull, BoxDynError> {\n            match self {\n                Value::String(s) => <String as Encode<'_, Postgres>>::encode_by_ref(s, buf),\n                Value::Number(n) => <i32 as Encode<'_, Postgres>>::encode_by_ref(n, buf),\n                Value::Array(arr) => arr.encode(buf),\n            }\n        }\n    }\n\n    impl Type<Postgres> for Value {\n        fn type_info() -> PgTypeInfo {\n            PgTypeInfo::with_name(\"unknown\")\n        }\n\n        fn compatible(ty: &PgTypeInfo) -> bool {\n            [\n                PgTypeInfo::with_name(\"text\"),\n                PgTypeInfo::with_name(\"_text\"),\n                PgTypeInfo::with_name(\"int4\"),\n                PgTypeInfo::with_name(\"_int4\"),\n            ]\n            .contains(ty)\n        }\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    let (row,): (Value,) = sqlx::query_as(\"SELECT $1::text[] as Dummy\")\n        .bind(Value::Array(vec![\n            Value::String(\"Test 0\".to_string()),\n            Value::String(\"Test 1\".to_string()),\n        ]))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(\n        row,\n        Value::Array(vec![\n            Value::String(\"Test 0\".to_string()),\n            Value::String(\"Test 1\".to_string()),\n        ])\n    );\n\n    let (row,): (Value,) = sqlx::query_as(\"SELECT $1::int4[] as Dummy\")\n        .bind(Value::Array(vec![\n            Value::Number(3),\n            Value::Number(2),\n            Value::Number(1),\n        ]))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(\n        row,\n        Value::Array(vec![Value::Number(3), Value::Number(2), Value::Number(1)])\n    );\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_issue_1254() -> anyhow::Result<()> {\n    #[derive(sqlx::Type)]\n    #[sqlx(type_name = \"pair\")]\n    struct Pair {\n        one: i32,\n        two: i32,\n    }\n\n    // array for custom type is not supported, use wrapper\n    #[derive(sqlx::Type)]\n    #[sqlx(type_name = \"_pair\")]\n    struct Pairs(Vec<Pair>);\n\n    let mut conn = new::<Postgres>().await?;\n    conn.execute(\n        \"\nDROP TABLE IF EXISTS issue_1254;\nDROP TYPE IF EXISTS pair;\n\nCREATE TYPE pair AS (one INT4, two INT4);\nCREATE TABLE issue_1254 (id INT4 PRIMARY KEY, pairs PAIR[]);\n\",\n    )\n    .await?;\n\n    let result = sqlx::query(\"INSERT INTO issue_1254 VALUES($1, $2)\")\n        .bind(0)\n        .bind(Pairs(vec![Pair { one: 94, two: 87 }]))\n        .execute(&mut conn)\n        .await?;\n    assert_eq!(result.rows_affected(), 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_advisory_locks() -> anyhow::Result<()> {\n    let pool = PgPoolOptions::new()\n        .max_connections(2)\n        .connect(&dotenvy::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let lock1 = Arc::new(PgAdvisoryLock::new(\"sqlx-postgres-tests-1\"));\n    let lock2 = Arc::new(PgAdvisoryLock::new(\"sqlx-postgres-tests-2\"));\n\n    let conn1 = pool.acquire().await?;\n    let mut conn1_lock1 = lock1.acquire(conn1).await?;\n\n    // try acquiring a recursive lock through a mutable reference then dropping\n    drop(lock1.acquire(&mut conn1_lock1).await?);\n\n    let conn2 = pool.acquire().await?;\n    // leak so we can take it across the task boundary\n    let conn2_lock2 = lock2.acquire(conn2).await?.leak();\n\n    sqlx_core::rt::spawn({\n        let lock1 = lock1.clone();\n        let lock2 = lock2.clone();\n\n        async move {\n            let conn2_lock2 = lock1.try_acquire(conn2_lock2).await?.right_or_else(|_| {\n                panic!(\n                    \"acquired lock but wasn't supposed to! Key: {:?}\",\n                    lock1.key()\n                )\n            });\n\n            let (conn2, released) = lock2.force_release(conn2_lock2).await?;\n            assert!(released);\n\n            // acquire both locks but let the pool release them\n            let conn2_lock1 = lock1.acquire(conn2).await?;\n            let _conn2_lock1and2 = lock2.acquire(conn2_lock1).await?;\n\n            anyhow::Ok(())\n        }\n    });\n\n    // acquire lock2 on conn1, we leak the lock1 guard so we can manually release it before lock2\n    let conn1_lock1and2 = lock2.acquire(conn1_lock1.leak()).await?;\n\n    // release lock1 while holding lock2\n    let (conn1_lock2, released) = lock1.force_release(conn1_lock1and2).await?;\n    assert!(released);\n\n    let conn1 = conn1_lock2.release_now().await?;\n\n    // acquire both locks to be sure they were released\n    {\n        let conn1_lock1 = lock1.acquire(conn1).await?;\n        let _conn1_lock1and2 = lock2.acquire(conn1_lock1).await?;\n    }\n\n    pool.close().await;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_postgres_bytea_hex_deserialization_errors() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    conn.execute(\"SET bytea_output = 'escape';\").await?;\n    for value in [\"\", \"DEADBEEF\"] {\n        let query = format!(\"SELECT '\\\\x{value}'::bytea\");\n        let res: sqlx::Result<Vec<u8>> =\n            conn.fetch_one(AssertSqlSafe(query)).await?.try_get(0usize);\n        // Deserialization only supports hex format so this should error and definitely not panic.\n        res.unwrap_err();\n    }\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_shrink_buffers() -> anyhow::Result<()> {\n    // We don't really have a good way to test that `.shrink_buffers()` functions as expected\n    // without exposing a lot of internals, but we can at least be sure it doesn't\n    // materially affect the operation of the connection.\n\n    let mut conn = new::<Postgres>().await?;\n\n    // The connection buffer is only 8 KiB by default so this should definitely force it to grow.\n    let data = vec![0u8; 32 * 1024];\n\n    let ret: Vec<u8> = sqlx::query_scalar(\"SELECT $1::bytea\")\n        .bind(&data)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(ret, data);\n\n    conn.shrink_buffers();\n\n    let ret: i64 = sqlx::query_scalar(\"SELECT $1::int8\")\n        .bind(&12345678i64)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(ret, 12345678i64);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_error_handling_with_deferred_constraints() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    sqlx::query(\"CREATE TABLE IF NOT EXISTS deferred_constraint ( id INTEGER PRIMARY KEY )\")\n        .execute(&mut conn)\n        .await?;\n\n    sqlx::query(\"CREATE TABLE IF NOT EXISTS deferred_constraint_fk ( fk INTEGER CONSTRAINT deferred_fk REFERENCES deferred_constraint(id) DEFERRABLE INITIALLY DEFERRED )\")\n            .execute(&mut conn)\n            .await?;\n\n    let result: sqlx::Result<i32> =\n        sqlx::query_scalar(\"INSERT INTO deferred_constraint_fk VALUES (1) RETURNING fk\")\n            .fetch_one(&mut conn)\n            .await;\n\n    let err = result.unwrap_err();\n    let db_err = err.as_database_error().unwrap();\n    assert_eq!(db_err.constraint(), Some(\"deferred_fk\"));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\n#[cfg(feature = \"bigdecimal\")]\nasync fn test_issue_3052() {\n    use sqlx::types::BigDecimal;\n\n    // https://github.com/launchbadge/sqlx/issues/3052\n    // Previously, attempting to bind a `BigDecimal` would panic if the value was out of range.\n    // Now, we rewrite it to a sentinel value so that Postgres will return a range error.\n    let too_small: BigDecimal = \"1E-65536\".parse().unwrap();\n    let too_large: BigDecimal = \"1E262144\".parse().unwrap();\n\n    let mut conn = new::<Postgres>().await.unwrap();\n\n    let too_small_error = sqlx::query_scalar::<_, BigDecimal>(\"SELECT $1::numeric\")\n        .bind(&too_small)\n        .fetch_one(&mut conn)\n        .await\n        .expect_err(\"Too small number should have failed\");\n    assert!(\n        matches!(&too_small_error, sqlx::Error::Encode(_)),\n        \"expected encode error, got {too_small_error:?}\"\n    );\n\n    let too_large_error = sqlx::query_scalar::<_, BigDecimal>(\"SELECT $1::numeric\")\n        .bind(&too_large)\n        .fetch_one(&mut conn)\n        .await\n        .expect_err(\"Too large number should have failed\");\n\n    assert!(\n        matches!(&too_large_error, sqlx::Error::Encode(_)),\n        \"expected encode error, got {too_large_error:?}\",\n    );\n}\n\n#[sqlx_macros::test]\nasync fn test_bind_iter() -> anyhow::Result<()> {\n    use sqlx::postgres::PgBindIterExt;\n    use sqlx::types::chrono::{DateTime, Utc};\n\n    let mut conn = new::<Postgres>().await?;\n\n    #[derive(sqlx::FromRow, PartialEq, Debug)]\n    struct Person {\n        id: i64,\n        name: String,\n        birthdate: DateTime<Utc>,\n    }\n\n    let people: Vec<Person> = vec![\n        Person {\n            id: 1,\n            name: \"Alice\".into(),\n            birthdate: \"1984-01-01T00:00:00Z\".parse().unwrap(),\n        },\n        Person {\n            id: 2,\n            name: \"Bob\".into(),\n            birthdate: \"2000-01-01T00:00:00Z\".parse().unwrap(),\n        },\n    ];\n\n    sqlx::query(\n        r#\"\ncreate temporary table person(\n  id int8 primary key,\n  name text not null,\n  birthdate timestamptz not null\n)\"#,\n    )\n    .execute(&mut conn)\n    .await?;\n\n    let rows_affected =\n        sqlx::query(\"insert into person(id, name, birthdate) select * from unnest($1, $2, $3)\")\n            // owned value\n            .bind(people.iter().map(|p| p.id).bind_iter())\n            // borrowed value\n            .bind(people.iter().map(|p| &p.name).bind_iter())\n            .bind(people.iter().map(|p| &p.birthdate).bind_iter())\n            .execute(&mut conn)\n            .await?\n            .rows_affected();\n    assert_eq!(rows_affected, 2);\n\n    let p_query = sqlx::query_as::<_, Person>(\"select * from person order by id\")\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(people, p_query);\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_pg_copy_chunked() -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n\n    let mut row = \"1\".repeat(PG_COPY_MAX_DATA_LEN / 10 - 1);\n    row.push_str(\"\\n\");\n\n    // creates a payload with COPY_MAX_DATA_LEN + 1 as size\n    let mut payload = row.repeat(10);\n    payload.push_str(\"12345678\\n\");\n\n    assert_eq!(payload.len(), PG_COPY_MAX_DATA_LEN + 1);\n\n    let mut copy = conn.copy_in_raw(\"COPY products(name) FROM STDIN\").await?;\n\n    assert!(copy.send(payload.as_bytes()).await.is_ok());\n    assert!(copy.finish().await.is_ok());\n    Ok(())\n}\n\nasync fn test_copy_in_error_case(query: &str, expected_error: &str) -> anyhow::Result<()> {\n    let mut conn = new::<Postgres>().await?;\n    conn.execute(\"CREATE TEMPORARY TABLE IF NOT EXISTS invalid_copy_target (id int4)\")\n        .await?;\n    // Try the COPY operation\n    match conn.copy_in_raw(query).await {\n        Ok(_) => anyhow::bail!(\"expected error\"),\n        Err(e) => assert!(\n            e.to_string().contains(expected_error),\n            \"expected error to contain: {expected_error}, got: {e:?}\"\n        ),\n    }\n    // Verify connection is still usable\n    let value = sqlx::query(\"select 1 + 1\")\n        .try_map(|row: PgRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(2i32, value);\n    Ok(())\n}\n#[sqlx_macros::test]\nasync fn it_can_recover_from_copy_in_to_missing_table() -> anyhow::Result<()> {\n    test_copy_in_error_case(\n        r#\"\n        COPY nonexistent_table (id) FROM STDIN WITH (FORMAT CSV, HEADER);\n        \"#,\n        \"does not exist\",\n    )\n    .await\n}\n#[sqlx_macros::test]\nasync fn it_can_recover_from_copy_in_empty_query() -> anyhow::Result<()> {\n    test_copy_in_error_case(\"\", \"EmptyQuery\").await\n}\n#[sqlx_macros::test]\nasync fn it_can_recover_from_copy_in_syntax_error() -> anyhow::Result<()> {\n    test_copy_in_error_case(\n        r#\"\n        COPY FROM STDIN WITH (FORMAT CSV);\n        \"#,\n        \"syntax error\",\n    )\n    .await\n}\n#[sqlx_macros::test]\nasync fn it_can_recover_from_copy_in_invalid_params() -> anyhow::Result<()> {\n    test_copy_in_error_case(\n        r#\"\n        COPY invalid_copy_target FROM STDIN WITH (FORMAT CSV, INVALID_PARAM true);\n        \"#,\n        \"invalid_param\",\n    )\n    .await\n}\n"
  },
  {
    "path": "tests/postgres/query_builder.rs",
    "content": "use sqlx::postgres::Postgres;\nuse sqlx::query_builder::QueryBuilder;\nuse sqlx::Executor;\nuse sqlx::Type;\nuse sqlx::{Either, Execute};\nuse sqlx_test::new;\n\n#[test]\nfn test_new() {\n    let qb: QueryBuilder<Postgres> = QueryBuilder::new(\"SELECT * FROM users\");\n    assert_eq!(qb.sql(), \"SELECT * FROM users\");\n}\n\n#[test]\nfn test_push() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"SELECT * FROM users\");\n    let second_line = \" WHERE last_name LIKE '[A-N]%';\";\n    qb.push(second_line);\n\n    assert_eq!(\n        qb.sql(),\n        \"SELECT * FROM users WHERE last_name LIKE '[A-N]%';\".to_string(),\n    );\n}\n\n#[test]\n#[should_panic]\nfn test_push_panics_after_build_without_reset() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"SELECT * FROM users;\");\n\n    let _query = qb.build();\n\n    qb.push(\"SELECT * FROM users;\");\n}\n\n#[test]\nfn test_push_bind() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"SELECT * FROM users WHERE id = \");\n\n    qb.push_bind(42i32)\n        .push(\" OR membership_level = \")\n        .push_bind(3i32);\n\n    assert_eq!(\n        qb.sql(),\n        \"SELECT * FROM users WHERE id = $1 OR membership_level = $2\"\n    );\n}\n\n#[test]\nfn test_build() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"SELECT * FROM users\");\n\n    qb.push(\" WHERE id = \").push_bind(42i32);\n    let query = qb.build();\n\n    assert!(Execute::persistent(&query));\n    assert_eq!(query.sql(), \"SELECT * FROM users WHERE id = $1\");\n}\n\n#[test]\nfn test_reset() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"\");\n\n    {\n        let _query = qb\n            .push(\"SELECT * FROM users WHERE id = \")\n            .push_bind(42i32)\n            .build();\n    }\n\n    qb.reset();\n\n    assert_eq!(qb.sql(), \"\");\n}\n\n#[test]\nfn test_query_builder_reuse() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"\");\n\n    let _query = qb\n        .push(\"SELECT * FROM users WHERE id = \")\n        .push_bind(42i32)\n        .build();\n\n    qb.reset();\n\n    let query = qb.push(\"SELECT * FROM users WHERE id = 99\").build();\n\n    assert_eq!(query.sql(), \"SELECT * FROM users WHERE id = 99\");\n}\n\n#[test]\nfn test_query_builder_with_args() {\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"\");\n\n    let mut query = qb\n        .push(\"SELECT * FROM users WHERE id = \")\n        .push_bind(42i32)\n        .build();\n\n    let args = query.take_arguments().unwrap().unwrap();\n\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::with_arguments(query.sql().as_str(), args);\n    let query = qb.push(\" OR membership_level = \").push_bind(3i32).build();\n\n    assert_eq!(\n        query.sql(),\n        \"SELECT * FROM users WHERE id = $1 OR membership_level = $2\"\n    );\n}\n\n#[sqlx::test]\nasync fn test_max_number_of_binds() -> anyhow::Result<()> {\n    // The maximum number of binds is 65535 (u16::MAX), not 32567 (i16::MAX)\n    // as the protocol documentation would imply\n    //\n    // https://github.com/launchbadge/sqlx/issues/3464\n\n    let mut qb: QueryBuilder<Postgres> = QueryBuilder::new(\"SELECT ARRAY[\");\n\n    let mut elements = qb.separated(',');\n\n    let max_bind = u16::MAX as i32;\n\n    for i in 1..=max_bind {\n        elements.push_bind(i);\n    }\n\n    qb.push(\"]::int4[]\");\n\n    let mut conn = new::<Postgres>().await?;\n\n    // Indirectly ensures the macros support this many binds since this is what they use.\n    let describe = conn.describe(qb.sql()).await?;\n\n    match describe\n        .parameters\n        .expect(\"describe() returned no parameter information\")\n    {\n        Either::Left(params) => {\n            assert_eq!(params.len(), 65535);\n\n            for param in params {\n                assert_eq!(param, <i32 as Type<Postgres>>::type_info())\n            }\n        }\n        Either::Right(num_params) => {\n            assert_eq!(num_params, 65535);\n        }\n    }\n\n    let values: Vec<i32> = qb.build_query_scalar().fetch_one(&mut conn).await?;\n\n    assert_eq!(values.len(), 65535);\n\n    for (idx, (i, j)) in (1..=max_bind).zip(values).enumerate() {\n        assert_eq!(i, j, \"mismatch at index {idx}\");\n    }\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/rustsec.rs",
    "content": "use sqlx::{Error, PgPool};\nuse sqlx_core::sql_str::AssertSqlSafe;\n\nuse std::{cmp, str};\n\n// https://rustsec.org/advisories/RUSTSEC-2024-0363.html\n#[sqlx::test(migrations = false, fixtures(\"./fixtures/rustsec/2024_0363.sql\"))]\nasync fn rustsec_2024_0363(pool: PgPool) -> anyhow::Result<()> {\n    let overflow_len = 4 * 1024 * 1024 * 1024; // 4 GiB\n\n    // These three strings concatenated together will be the first query the Postgres backend \"sees\"\n    //\n    // Rather contrived because this already represents an injection vulnerability,\n    // but it's easier to demonstrate the bug with a simple `Query` message\n    // than the `Prepare` -> `Bind` -> `Execute` flow.\n    let real_query_prefix = \"INSERT INTO injection_target(message) VALUES ('\";\n    let fake_message = \"fake_msg') RETURNING id;\\0\";\n    let real_query_suffix = \"') RETURNING id\";\n\n    // Our payload is another simple `Query` message\n    let real_payload =\n        \"Q\\0\\0\\0\\x4DUPDATE injection_target SET message = 'you''ve been pwned!' WHERE id = 1\\0\";\n\n    // This is the value we want the length prefix to overflow to (including the length of the prefix itself)\n    // This will leave the backend's buffer pointing at our real payload.\n    let fake_payload_len = real_query_prefix.len() + fake_message.len() + 4;\n\n    // Pretty easy to see that this should overflow to `fake_payload_len`\n    let target_payload_len = overflow_len + fake_payload_len;\n\n    // This is the length we expect `injected_value` to be\n    let expected_inject_len = target_payload_len\n        - 4 // Length prefix\n        - real_query_prefix.len()\n        - (real_query_suffix.len() + 1 /* NUL terminator */);\n\n    let pad_to_len = expected_inject_len - 5; // Header for FLUSH message that eats `real_query_suffix` (see below)\n\n    let expected_payload_len = 4 // length prefix\n        + real_query_prefix.len()\n        + expected_inject_len\n        + real_query_suffix.len()\n        + 1; // NUL terminator\n\n    let expected_wrapped_len = expected_payload_len % overflow_len;\n    assert_eq!(expected_wrapped_len, fake_payload_len);\n\n    // This will be the string we inject into the query.\n    let mut injected_value = String::with_capacity(expected_inject_len);\n\n    injected_value.push_str(fake_message);\n    injected_value.push_str(real_payload);\n\n    // The Postgres backend reads the `FLUSH` message but ignores its contents.\n    // This gives us a variable-length NOP that lets us pad to the length we want,\n    // as well as a way to eat `real_query_suffix` without breaking the connection.\n    let flush_fill = \"\\0\".repeat(9996);\n\n    let flush_fmt_code = 'H'; // note: 'F' is `FunctionCall`.\n\n    'outer: while injected_value.len() < pad_to_len {\n        let remaining_len = pad_to_len - injected_value.len();\n\n        // The max length of a FLUSH message is 10,000, including the length prefix.\n        let flush_len = cmp::min(\n            remaining_len - 1, // minus format code\n            10000,\n        );\n\n        // We need `flush_len` to be valid UTF-8 when encoded in big-endian\n        // in order to push it to the string.\n        //\n        // Not every value is going to be valid though, so we search for one that is.\n        'inner: for flush_len in (4..=flush_len).rev() {\n            let flush_len_be = (flush_len as i32).to_be_bytes();\n\n            let Ok(flush_len_str) = str::from_utf8(&flush_len_be) else {\n                continue 'inner;\n            };\n\n            let fill_len = flush_len - 4;\n\n            injected_value.push(flush_fmt_code);\n            injected_value.push_str(flush_len_str);\n            injected_value.push_str(&flush_fill[..fill_len]);\n\n            continue 'outer;\n        }\n\n        panic!(\"unable to find a valid encoding/split for {flush_len}\");\n    }\n\n    assert_eq!(injected_value.len(), pad_to_len);\n\n    // The amount of data the last FLUSH message has to eat\n    let eat_len = real_query_suffix.len() + 1; // plus NUL terminator\n\n    // Push the FLUSH message that will eat `real_query_suffix`\n    injected_value.push(flush_fmt_code);\n    injected_value.push_str(str::from_utf8(&(eat_len as i32).to_be_bytes()).unwrap());\n    // The value will be in the buffer already.\n\n    assert_eq!(expected_inject_len, injected_value.len());\n\n    let query = format!(\"{real_query_prefix}{injected_value}{real_query_suffix}\");\n\n    // The length of the `Query` message we've created\n    let final_payload_len = 4 // length prefix\n        + query.len()\n        + 1; // NUL terminator\n\n    assert_eq!(expected_payload_len, final_payload_len);\n\n    let wrapped_len = final_payload_len % overflow_len;\n\n    assert_eq!(wrapped_len, fake_payload_len);\n\n    let res = sqlx::raw_sql(AssertSqlSafe(query))\n        // Note: the connection may hang afterward\n        // because `pending_ready_for_query_count` will underflow.\n        .execute(&pool)\n        .await;\n\n    if let Err(e) = res {\n        // Connection rejected the query; we're happy.\n        if matches!(e, Error::Protocol(_)) {\n            return Ok(());\n        }\n\n        panic!(\"unexpected error: {e:?}\");\n    }\n\n    let messages: Vec<String> =\n        sqlx::query_scalar(\"SELECT message FROM injection_target ORDER BY id\")\n            .fetch_all(&pool)\n            .await?;\n\n    // If the injection succeeds, `messages` will look like:\n    // [\"you've been pwned!'.to_string(), \"fake_msg\".to_string()]\n    assert_eq!(\n        messages,\n        [\"existing message\".to_string(), \"fake_msg\".to_string()]\n    );\n\n    // Injection didn't affect our database; we're happy.\n    Ok(())\n}\n"
  },
  {
    "path": "tests/postgres/setup.sql",
    "content": "-- https://www.postgresql.org/docs/current/ltree.html\nCREATE EXTENSION IF NOT EXISTS ltree;\n\n-- https://www.postgresql.org/docs/current/cube.html\nCREATE EXTENSION IF NOT EXISTS cube;\n\n-- https://www.postgresql.org/docs/current/citext.html\nCREATE EXTENSION IF NOT EXISTS citext;\n\n-- https://www.postgresql.org/docs/current/hstore.html\nCREATE EXTENSION IF NOT EXISTS hstore;\n\n-- https://www.postgresql.org/docs/current/sql-createtype.html\nCREATE TYPE status AS ENUM ('new', 'open', 'closed');\n\n-- https://www.postgresql.org/docs/current/rowtypes.html#ROWTYPES-DECLARING\nCREATE TYPE inventory_item AS\n(\n    name        TEXT,\n    supplier_id INT,\n    price       BIGINT\n);\n\n-- https://github.com/prisma/database-schema-examples/tree/master/postgres/basic-twitter#basic-twitter\nCREATE TABLE tweet\n(\n    id         BIGSERIAL PRIMARY KEY,\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n    text       TEXT        NOT NULL,\n    owner_id   BIGINT\n);\n\nCREATE TABLE tweet_reply\n(\n    id         BIGSERIAL PRIMARY KEY,\n    tweet_id   BIGINT      NOT NULL REFERENCES tweet(id),\n    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n    text       TEXT        NOT NULL,\n    owner_id   BIGINT\n);\n\nCREATE TYPE float_range AS RANGE\n(\n    subtype = float8,\n    subtype_diff = float8mi\n);\n\nCREATE TABLE products (\n    product_no INTEGER,\n    name TEXT,\n    price NUMERIC CHECK (price > 0)\n);\n\nCREATE OR REPLACE PROCEDURE forty_two(INOUT forty_two INT = NULL)\n    LANGUAGE plpgsql AS 'begin forty_two := 42; end;';\n\nCREATE TABLE test_citext (\n    foo CITEXT NOT NULL\n);\n\nCREATE SCHEMA IF NOT EXISTS foo;\n\nCREATE TYPE foo.\"Foo\" as ENUM ('Bar', 'Baz');\n\nCREATE TABLE mytable(f HSTORE);\n\nCREATE TABLE circles (\n    c circle,\n    EXCLUDE USING gist (c WITH &&)\n);\n\nCREATE DOMAIN positive_int AS integer CHECK (VALUE > 0);\nCREATE DOMAIN percentage AS positive_int CHECK (VALUE <= 100);\n\nCREATE TYPE person as (\n    id int,\n    age positive_int,\n    percent percentage\n);\n\nCREATE TYPE leaf_composite AS (prim integer);\nCREATE DOMAIN domain AS leaf_composite;\nCREATE TYPE root_composite AS (domain domain);\n"
  },
  {
    "path": "tests/postgres/test-attr.rs",
    "content": "// The no-arg variant is covered by other tests already.\n\nuse sqlx::PgPool;\n\nconst MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!(\"tests/postgres/migrations\");\n\n#[sqlx::test]\nasync fn it_gets_a_pool(pool: PgPool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n\n    let db_name: String = sqlx::query_scalar(\"SELECT current_database()\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    assert!(db_name.starts_with(\"_sqlx_test\"), \"dbname: {db_name:?}\");\n\n    Ok(())\n}\n\n// This should apply migrations and then `fixtures/users.sql`\n#[sqlx::test(migrations = \"tests/postgres/migrations\", fixtures(\"users\"))]\nasync fn it_gets_users(pool: PgPool) -> sqlx::Result<()> {\n    let usernames: Vec<String> =\n        sqlx::query_scalar(r#\"SELECT username FROM \"user\" ORDER BY username\"#)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(usernames, [\"alice\", \"bob\"]);\n\n    let post_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM post)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!post_exists);\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// This should apply migrations and then fixtures `fixtures/users.sql` and `fixtures/posts.sql`\n#[sqlx::test(migrations = \"tests/postgres/migrations\", fixtures(\"users\", \"posts\"))]\nasync fn it_gets_posts(pool: PgPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// This should apply migrations and then `../fixtures/postgres/users.sql` and `../fixtures/postgres/posts.sql`\n#[sqlx::test(\n    migrations = \"tests/postgres/migrations\",\n    fixtures(\"../fixtures/postgres/users.sql\", \"../fixtures/postgres/posts.sql\")\n)]\nasync fn it_gets_posts_explicit_fixtures_path(pool: PgPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// This should apply migrations and then `../fixtures/postgres/users.sql` and `fixtures/posts.sql`\n#[sqlx::test(\n    migrations = \"tests/postgres/migrations\",\n    fixtures(\"../fixtures/postgres/users.sql\"),\n    fixtures(\"posts\")\n)]\nasync fn it_gets_posts_mixed_fixtures_path(pool: PgPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// This should apply migrations and then `../fixtures/postgres/users.sql` and `../fixtures/postgres/posts.sql`\n#[sqlx::test(\n    migrations = \"tests/postgres/migrations\",\n    fixtures(\"../fixtures/postgres/users.sql\", \"../fixtures/postgres/posts.sql\")\n)]\nasync fn it_gets_posts_custom_relative_fixtures_path(pool: PgPool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// Try `migrator`\n#[sqlx::test(migrator = \"MIGRATOR\", fixtures(\"users\", \"posts\", \"comments\"))]\nasync fn it_gets_comments(pool: PgPool) -> sqlx::Result<()> {\n    let post_1_comments: Vec<String> = sqlx::query_scalar(\n        \"SELECT content FROM comment WHERE post_id = $1::uuid ORDER BY created_at\",\n    )\n    .bind(\"252c1d98-a9b0-4f18-8298-e59058bdfe16\")\n    .fetch_all(&pool)\n    .await?;\n\n    assert_eq!(\n        post_1_comments,\n        [\"lol bet ur still bad, 1v1 me\", \"you're on!\"]\n    );\n\n    let post_2_comments: Vec<String> = sqlx::query_scalar(\n        \"SELECT content FROM comment WHERE post_id = $1::uuid ORDER BY created_at\",\n    )\n    .bind(\"844265f7-2472-4689-9a2e-b21f40dbf401\")\n    .fetch_all(&pool)\n    .await?;\n\n    assert_eq!(post_2_comments, [\"lol you're just mad you lost :P\"]);\n\n    Ok(())\n}\n\n#[sqlx::test(\n    migrations = \"tests/postgres/migrations\",\n    fixtures(path = \"../fixtures/postgres\", scripts(\"users\", \"posts\"))\n)]\nasync fn this_should_compile(_pool: PgPool) -> sqlx::Result<()> {\n    Ok(())\n}\n\nmacro_rules! macro_using_test {\n    ($migrations: literal) => {\n        #[sqlx::test(\n                            migrations = $migrations,\n                            fixtures(path = \"../fixtures/postgres\", scripts(\"users\", \"posts\"))\n                        )]\n        async fn macro_using_macro(_pool: PgPool) -> sqlx::Result<()> {\n            Ok(())\n        }\n    };\n}\nmacro_using_test!(\"tests/postgres/migrations\");\n"
  },
  {
    "path": "tests/postgres/test-query.sql",
    "content": "SELECT id \"id!\", name from (VALUES (1, null)) accounts(id, name)\n"
  },
  {
    "path": "tests/postgres/types.rs",
    "content": "extern crate time_ as time;\n\nuse std::borrow::Cow;\nuse std::net::SocketAddr;\nuse std::ops::Bound;\nuse std::rc::Rc;\nuse std::str::FromStr;\nuse std::sync::Arc;\n\nuse sqlx::postgres::types::{Oid, PgCiText, PgInterval, PgMoney, PgRange};\nuse sqlx::postgres::Postgres;\nuse sqlx_test::{new, test_decode_type, test_prepared_type, test_type};\n\nuse sqlx_core::executor::Executor;\nuse sqlx_core::types::Text;\n\ntest_type!(null<Option<i16>>(Postgres,\n    \"NULL::int2\" == None::<i16>\n));\n\ntest_type!(null_vec<Vec<Option<i16>>>(Postgres,\n    \"array[10,NULL,50]::int2[]\" == vec![Some(10_i16), None, Some(50)],\n));\n\ntest_type!(null_array<[Option<i16>; 3]>(Postgres,\n    \"array[10,NULL,50]::int2[]\" == vec![Some(10_i16), None, Some(50)],\n));\n\ntest_type!(bool<bool>(Postgres,\n    \"false::boolean\" == false,\n    \"true::boolean\" == true\n));\n\ntest_type!(bool_vec<Vec<bool>>(Postgres,\n    \"array[true,false,true]::bool[]\" == vec![true, false, true],\n));\n\ntest_type!(bool_array<[bool; 3]>(Postgres,\n    \"array[true,false,true]::bool[]\" == vec![true, false, true],\n));\n\ntest_type!(byte_vec<Vec<u8>>(Postgres,\n    \"E'\\\\\\\\xDEADBEEF'::bytea\"\n        == vec![0xDE_u8, 0xAD, 0xBE, 0xEF],\n    \"E'\\\\\\\\x'::bytea\"\n        == Vec::<u8>::new(),\n    \"E'\\\\\\\\x0000000052'::bytea\"\n        == vec![0_u8, 0, 0, 0, 0x52]\n));\n\n// BYTEA cannot be decoded by-reference from a simple query as postgres sends it as hex\ntest_prepared_type!(byte_slice<&[u8]>(Postgres,\n    \"E'\\\\\\\\xDEADBEEF'::bytea\"\n        == &[0xDE_u8, 0xAD, 0xBE, 0xEF][..],\n    \"E'\\\\\\\\x0000000052'::bytea\"\n        == &[0_u8, 0, 0, 0, 0x52][..]\n));\n\ntest_type!(byte_array_empty<[u8; 0]>(Postgres,\n    \"E'\\\\\\\\x'::bytea\" == [0_u8; 0],\n));\n\ntest_type!(byte_array<[u8; 4]>(Postgres,\n    \"E'\\\\\\\\xDEADBEEF'::bytea\" == [0xDE_u8, 0xAD, 0xBE, 0xEF],\n));\n\ntest_type!(str<&str>(Postgres,\n    \"'this is foo'\" == \"this is foo\",\n    \"''\" == \"\",\n    \"'identifier'::name\" == \"identifier\",\n    \"'five'::char(4)\" == \"five\",\n    \"'more text'::varchar\" == \"more text\",\n    \"'case insensitive searching'::citext\" == \"case insensitive searching\",\n));\n\ntest_type!(string<String>(Postgres,\n    \"'this is foo'\" == format!(\"this is foo\"),\n));\n\ntest_type!(string_vec<Vec<String>>(Postgres,\n    \"array['one','two','three']::text[]\"\n        == vec![\"one\",\"two\",\"three\"],\n\n    \"array['', '\\\"']::text[]\"\n        == vec![\"\", \"\\\"\"],\n\n    \"array['Hello, World', '', 'Goodbye']::text[]\"\n        == vec![\"Hello, World\", \"\", \"Goodbye\"],\n));\n\ntest_type!(string_array<[String; 3]>(Postgres,\n    \"array['one','two','three']::text[]\" == [\"one\",\"two\",\"three\"],\n));\n\ntest_type!(i8(\n    Postgres,\n    \"0::\\\"char\\\"\" == 0_i8,\n    \"120::\\\"char\\\"\" == 120_i8,\n));\n\ntest_type!(Oid(Postgres, \"325235::oid\" == Oid(325235),));\n\ntest_type!(i16(\n    Postgres,\n    \"-2144::smallint\" == -2144_i16,\n    \"821::smallint\" == 821_i16,\n));\n\ntest_type!(i32(\n    Postgres,\n    \"94101::int\" == 94101_i32,\n    \"-5101::int\" == -5101_i32\n));\n\ntest_type!(i32_vec<Vec<i32>>(Postgres,\n    \"'{5,10,50,100}'::int[]\" == vec![5_i32, 10, 50, 100],\n    \"'{1050}'::int[]\" == vec![1050_i32],\n    \"'{}'::int[]\" == Vec::<i32>::new(),\n    \"'{1,3,-5}'::int[]\" == vec![1_i32, 3, -5]\n));\n\ntest_type!(i32_array_empty<[i32; 0]>(Postgres,\n    \"'{}'::int[]\" == [0_i32; 0],\n));\n\ntest_type!(i32_array<[i32; 4]>(Postgres,\n    \"'{5,10,50,100}'::int[]\" == [5_i32, 10, 50, 100],\n));\n\ntest_type!(i64(Postgres, \"9358295312::bigint\" == 9358295312_i64));\n\ntest_type!(f32(Postgres, \"9419.122::real\" == 9419.122_f32));\n\ntest_type!(f64(\n    Postgres,\n    \"939399419.1225182::double precision\" == 939399419.1225182_f64\n));\n\ntest_type!(f64_vec<Vec<f64>>(Postgres,\n    \"'{939399419.1225182,-12.0}'::float8[]\" == vec![939399419.1225182_f64, -12.0]\n));\n\ntest_decode_type!(bool_tuple<(bool,)>(Postgres, \"row(true)\" == (true,)));\n\ntest_decode_type!(num_tuple<(i32, i64, f64,)>(Postgres, \"row(10,515::int8,3.124::float8)\" == (10,515,3.124)));\n\ntest_decode_type!(empty_tuple<()>(Postgres, \"row()\" == ()));\n\ntest_decode_type!(string_tuple<(String, String, String)>(Postgres,\n    \"row('one','two','three')\"\n        == (\"one\".to_string(), \"two\".to_string(), \"three\".to_string()),\n\n    \"row('', '\\\"', '\\\"\\\"\\\"\\\"\\\"\\\"')\"\n        == (\"\".to_string(), \"\\\"\".to_string(), \"\\\"\\\"\\\"\\\"\\\"\\\"\".to_string()),\n\n    \"row('Hello, World', '', 'Goodbye')\"\n        == (\"Hello, World\".to_string(), \"\".to_string(), \"Goodbye\".to_string())\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid<sqlx::types::Uuid>(Postgres,\n    \"'b731678f-636f-4135-bc6f-19440c13bd19'::uuid\"\n        == sqlx::types::Uuid::parse_str(\"b731678f-636f-4135-bc6f-19440c13bd19\").unwrap(),\n    \"'00000000-0000-0000-0000-000000000000'::uuid\"\n        == sqlx::types::Uuid::parse_str(\"00000000-0000-0000-0000-000000000000\").unwrap()\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid_vec<Vec<sqlx::types::Uuid>>(Postgres,\n    \"'{b731678f-636f-4135-bc6f-19440c13bd19,00000000-0000-0000-0000-000000000000}'::uuid[]\"\n        == vec![\n           sqlx::types::Uuid::parse_str(\"b731678f-636f-4135-bc6f-19440c13bd19\").unwrap(),\n           sqlx::types::Uuid::parse_str(\"00000000-0000-0000-0000-000000000000\").unwrap()\n        ]\n));\n\n#[cfg(feature = \"ipnet\")]\ntest_type!(ipnet<sqlx::types::ipnet::IpNet>(Postgres,\n    \"'127.0.0.1'::inet\"\n        == \"127.0.0.1/32\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n    \"'8.8.8.8/24'::inet\"\n        == \"8.8.8.8/24\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n    \"'10.1.1/24'::inet\"\n        == \"10.1.1.0/24\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n    \"'::ffff:1.2.3.0'::inet\"\n        == \"::ffff:1.2.3.0/128\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n    \"'2001:4f8:3:ba::/64'::inet\"\n        == \"2001:4f8:3:ba::/64\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n    \"'192.168'::cidr\"\n        == \"192.168.0.0/24\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n    \"'::ffff:1.2.3.0/120'::cidr\"\n        == \"::ffff:1.2.3.0/120\"\n            .parse::<sqlx::types::ipnet::IpNet>()\n            .unwrap(),\n));\n\n#[cfg(feature = \"ipnetwork\")]\ntest_type!(ipnetwork<sqlx::types::ipnetwork::IpNetwork>(Postgres,\n    \"'127.0.0.1'::inet\"\n        == \"127.0.0.1\"\n            .parse::<sqlx::types::ipnetwork::IpNetwork>()\n            .unwrap(),\n    \"'8.8.8.8/24'::inet\"\n        == \"8.8.8.8/24\"\n            .parse::<sqlx::types::ipnetwork::IpNetwork>()\n            .unwrap(),\n    \"'::ffff:1.2.3.0'::inet\"\n        == \"::ffff:1.2.3.0\"\n            .parse::<sqlx::types::ipnetwork::IpNetwork>()\n            .unwrap(),\n    \"'2001:4f8:3:ba::/64'::inet\"\n        == \"2001:4f8:3:ba::/64\"\n            .parse::<sqlx::types::ipnetwork::IpNetwork>()\n            .unwrap(),\n    \"'192.168'::cidr\"\n        == \"192.168.0.0/24\"\n            .parse::<sqlx::types::ipnetwork::IpNetwork>()\n            .unwrap(),\n    \"'::ffff:1.2.3.0/120'::cidr\"\n        == \"::ffff:1.2.3.0/120\"\n            .parse::<sqlx::types::ipnetwork::IpNetwork>()\n            .unwrap(),\n));\n\n#[cfg(feature = \"mac_address\")]\ntest_type!(mac_address<sqlx::types::mac_address::MacAddress>(Postgres,\n    \"'00:01:02:03:04:05'::macaddr\"\n        == \"00:01:02:03:04:05\"\n            .parse::<sqlx::types::mac_address::MacAddress>()\n            .unwrap()\n));\n\n#[cfg(feature = \"bit-vec\")]\ntest_type!(bitvec<sqlx::types::BitVec>(\n    Postgres,\n    // A full byte VARBIT\n    \"B'01101001'\" == sqlx::types::BitVec::from_bytes(&[0b0110_1001]),\n    // A VARBIT value missing five bits from a byte\n    \"B'110'\" == {\n        let mut bit_vec = sqlx::types::BitVec::with_capacity(4);\n        bit_vec.push(true);\n        bit_vec.push(true);\n        bit_vec.push(false);\n        bit_vec\n    },\n    // A BIT value\n    \"B'01101'::bit(5)\" == {\n        let mut bit_vec = sqlx::types::BitVec::with_capacity(5);\n        bit_vec.push(false);\n        bit_vec.push(true);\n        bit_vec.push(true);\n        bit_vec.push(false);\n        bit_vec.push(true);\n        bit_vec\n    },\n));\n\n#[cfg(feature = \"ipnet\")]\ntest_type!(ipnet_vec<Vec<sqlx::types::ipnet::IpNet>>(Postgres,\n    \"'{127.0.0.1,8.8.8.8/24}'::inet[]\"\n        == vec![\n           \"127.0.0.1/32\".parse::<sqlx::types::ipnet::IpNet>().unwrap(),\n           \"8.8.8.8/24\".parse::<sqlx::types::ipnet::IpNet>().unwrap()\n        ]\n));\n\n#[cfg(feature = \"ipnetwork\")]\ntest_type!(ipnetwork_vec<Vec<sqlx::types::ipnetwork::IpNetwork>>(Postgres,\n    \"'{127.0.0.1,8.8.8.8/24}'::inet[]\"\n        == vec![\n           \"127.0.0.1\".parse::<sqlx::types::ipnetwork::IpNetwork>().unwrap(),\n           \"8.8.8.8/24\".parse::<sqlx::types::ipnetwork::IpNetwork>().unwrap()\n        ]\n));\n\n#[cfg(feature = \"mac_address\")]\ntest_type!(mac_address_vec<Vec<sqlx::types::mac_address::MacAddress>>(Postgres,\n    \"'{01:02:03:04:05:06,FF:FF:FF:FF:FF:FF}'::macaddr[]\"\n        == vec![\n           \"01:02:03:04:05:06\".parse::<sqlx::types::mac_address::MacAddress>().unwrap(),\n           \"FF:FF:FF:FF:FF:FF\".parse::<sqlx::types::mac_address::MacAddress>().unwrap()\n        ]\n));\n\n#[cfg(feature = \"chrono\")]\nmod chrono {\n    use super::*;\n    use sqlx::types::chrono::{\n        DateTime, FixedOffset, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Utc,\n    };\n\n    type PgTimeTz = sqlx::postgres::types::PgTimeTz<NaiveTime, FixedOffset>;\n\n    test_type!(chrono_date<NaiveDate>(Postgres,\n        \"DATE '2001-01-05'\" == NaiveDate::from_ymd_opt(2001, 1, 5).unwrap(),\n        \"DATE '2050-11-23'\" == NaiveDate::from_ymd_opt(2050, 11, 23).unwrap()\n    ));\n\n    test_type!(chrono_time<NaiveTime>(Postgres,\n        \"TIME '05:10:20.115100'\" == NaiveTime::from_hms_micro_opt(5, 10, 20, 115100).unwrap()\n    ));\n\n    test_type!(chrono_date_time<NaiveDateTime>(Postgres,\n        \"'2019-01-02 05:10:20'::timestamp\" == NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_opt(5, 10, 20).unwrap()\n    ));\n\n    test_type!(chrono_date_time_vec<Vec<NaiveDateTime>>(Postgres,\n        \"array['2019-01-02 05:10:20']::timestamp[]\"\n            == vec![NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_opt(5, 10, 20).unwrap()]\n    ));\n\n    test_type!(chrono_date_time_tz_utc<DateTime::<Utc>>(Postgres,\n        \"TIMESTAMPTZ '2019-01-02 05:10:20.115100'\"\n            == Utc.from_utc_datetime(\n                &NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_micro_opt(5, 10, 20, 115100).unwrap(),\n            )\n    ));\n\n    test_type!(chrono_date_time_tz<DateTime::<FixedOffset>>(Postgres,\n        \"TIMESTAMPTZ '2019-01-02 05:10:20.115100+06:30'\"\n            == FixedOffset::east_opt(60 * 60 * 6 + 1800)\n                .unwrap()\n                .from_local_datetime(\n                    &NaiveDate::from_ymd_opt(2019, 1, 2)\n                        .unwrap()\n                        .and_hms_micro_opt(5, 10, 20, 115_100)\n                        .unwrap()\n                )\n                .unwrap()\n    ));\n\n    test_type!(chrono_date_time_tz_vec<Vec<DateTime::<Utc>>>(Postgres,\n        \"array['2019-01-02 05:10:20.115100']::timestamptz[]\"\n            == vec![\n                Utc.from_utc_datetime(\n                    &NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_micro_opt(5, 10, 20, 115100).unwrap(),\n                )\n            ]\n    ));\n\n    test_type!(chrono_time_tz<PgTimeTz>(Postgres,\n        \"TIMETZ '05:10:20.115100+00'\" == PgTimeTz { time: NaiveTime::from_hms_micro_opt(5, 10, 20, 115100).unwrap(), offset: FixedOffset::east_opt(0).unwrap() },\n        \"TIMETZ '05:10:20.115100+06:30'\" == PgTimeTz { time: NaiveTime::from_hms_micro_opt(5, 10, 20, 115100).unwrap(), offset: FixedOffset::east_opt(60 * 60 * 6 + 1800).unwrap() },\n        \"TIMETZ '05:10:20.115100-05'\" == PgTimeTz { time: NaiveTime::from_hms_micro_opt(5, 10, 20, 115100).unwrap(), offset: FixedOffset::west_opt(60 * 60 * 5).unwrap() },\n        \"TIMETZ '05:10:20+02'\" == PgTimeTz { time: NaiveTime::from_hms_opt(5, 10, 20).unwrap(), offset: FixedOffset::east_opt(60 * 60 * 2 ).unwrap() }\n    ));\n}\n\n#[cfg(feature = \"time\")]\nmod time_tests {\n    use super::*;\n    use sqlx::types::time::{Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset};\n    use time::macros::{date, time};\n\n    type PgTimeTz = sqlx::postgres::types::PgTimeTz<Time, UtcOffset>;\n\n    test_type!(time_date<Date>(\n        Postgres,\n        \"DATE '2001-01-05'\" == date!(2001 - 1 - 5),\n        \"DATE '2050-11-23'\" == date!(2050 - 11 - 23)\n    ));\n\n    test_type!(time_time<Time>(\n        Postgres,\n        \"TIME '05:10:20.115100'\" == time!(5:10:20.115100),\n        \"TIME '05:10:20'\" == time!(5:10:20)\n    ));\n\n    test_type!(time_date_time<PrimitiveDateTime>(\n        Postgres,\n        \"TIMESTAMP '2019-01-02 05:10:20'\" == date!(2019 - 1 - 2).with_time(time!(5:10:20)),\n        \"TIMESTAMP '2019-01-02 05:10:20.1151'\" == date!(2019 - 1 - 2).with_time(time!(5:10:20.115100))\n    ));\n\n    test_type!(time_timestamp<OffsetDateTime>(\n        Postgres,\n        \"TIMESTAMPTZ '2019-01-02 05:10:20.115100'\"\n            == date!(2019 - 1 - 2)\n                .with_time(time!(5:10:20.115100))\n                .assume_utc()\n    ));\n\n    test_prepared_type!(time_time_tz<PgTimeTz>(Postgres,\n        \"TIMETZ '05:10:20.115100+00'\" == PgTimeTz { time: time!(5:10:20.115100), offset: UtcOffset::from_whole_seconds(0).unwrap() },\n        \"TIMETZ '05:10:20.115100+00'\" == PgTimeTz { time: time!(5:10:20.115100), offset: UtcOffset::from_whole_seconds(0).unwrap() },\n        \"TIMETZ '05:10:20.115100+06:30'\" == PgTimeTz { time: time!(5:10:20.115100), offset: UtcOffset::from_whole_seconds(60 * 60 * 6 + 1800).unwrap() },\n        \"TIMETZ '05:10:20.115100-05'\" == PgTimeTz { time: time!(5:10:20.115100), offset: UtcOffset::from_whole_seconds(-(60 * 60 * 5)).unwrap() },\n        \"TIMETZ '05:10:20+02'\" == PgTimeTz { time: time!(5:10:20), offset: UtcOffset::from_whole_seconds(60 * 60 * 2 ).unwrap() }\n    ));\n}\n\n#[cfg(feature = \"json\")]\nmod json {\n    use super::*;\n    use serde_json::value::RawValue as JsonRawValue;\n    use serde_json::{json, Value as JsonValue};\n    use sqlx::postgres::PgRow;\n    use sqlx::types::Json;\n    use sqlx::{Executor, Row};\n    use sqlx_test::new;\n\n    // When testing JSON, coerce to JSONB for `=` comparison as `JSON = JSON` is not\n    // supported in PostgreSQL\n\n    test_type!(json<JsonValue>(\n        Postgres,\n        \"SELECT ({0}::jsonb is not distinct from $1::jsonb)::int4, {0} as _2, $2 as _3\",\n        \"'\\\"Hello, World\\\"'::json\" == json!(\"Hello, World\"),\n        \"'\\\"😎\\\"'::json\" == json!(\"😎\"),\n        \"'\\\"🙋‍♀️\\\"'::json\" == json!(\"🙋‍♀️\"),\n        \"'[\\\"Hello\\\", \\\"World!\\\"]'::json\" == json!([\"Hello\", \"World!\"])\n    ));\n\n    test_type!(json_vec<Vec<JsonValue>>(\n        Postgres,\n        \"SELECT ({0}::jsonb[] is not distinct from $1::jsonb[])::int4, {0} as _2, $2 as _3\",\n        \"array['\\\"😎\\\"'::json, '\\\"🙋‍♀️\\\"'::json]::json[]\" == vec![json!(\"😎\"), json!(\"🙋‍♀️\")],\n    ));\n\n    test_type!(json_array<[JsonValue; 2]>(\n        Postgres,\n        \"SELECT ({0}::jsonb[] is not distinct from $1::jsonb[])::int4, {0} as _2, $2 as _3\",\n        \"array['\\\"😎\\\"'::json, '\\\"🙋‍♀️\\\"'::json]::json[]\" == [json!(\"😎\"), json!(\"🙋‍♀️\")],\n    ));\n\n    test_type!(jsonb<JsonValue>(\n        Postgres,\n        \"'\\\"Hello, World\\\"'::jsonb\" == json!(\"Hello, World\"),\n        \"'\\\"😎\\\"'::jsonb\" == json!(\"😎\"),\n        \"'\\\"🙋‍♀️\\\"'::jsonb\" == json!(\"🙋‍♀️\"),\n        \"'[\\\"Hello\\\", \\\"World!\\\"]'::jsonb\" == json!([\"Hello\", \"World!\"])\n    ));\n\n    test_type!(jsonb_array<Vec<JsonValue>>(\n        Postgres,\n        \"array['\\\"😎\\\"'::jsonb, '\\\"🙋‍♀️\\\"'::jsonb]::jsonb[]\" == vec![json!(\"😎\"), json!(\"🙋‍♀️\")],\n    ));\n\n    #[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq)]\n    struct Friend {\n        name: String,\n        age: u32,\n    }\n\n    test_type!(json_struct<Json<Friend>>(Postgres,\n        \"'{\\\"name\\\":\\\"Joe\\\",\\\"age\\\":33}'::jsonb\" == Json(Friend { name: \"Joe\".to_string(), age: 33 })\n    ));\n\n    test_type!(json_struct_vec<Vec<Json<Friend>>>(Postgres,\n        \"array['{\\\"name\\\":\\\"Joe\\\",\\\"age\\\":33}','{\\\"name\\\":\\\"Bob\\\",\\\"age\\\":22}']::jsonb[]\"\n            == vec![\n                Json(Friend { name: \"Joe\".to_string(), age: 33 }),\n                Json(Friend { name: \"Bob\".to_string(), age: 22 }),\n            ]\n    ));\n\n    #[sqlx_macros::test]\n    async fn test_json_raw_value() -> anyhow::Result<()> {\n        let mut conn = new::<Postgres>().await?;\n\n        // unprepared, text API\n        let row: PgRow = conn\n            .fetch_one(\"SELECT '{\\\"hello\\\": \\\"world\\\"}'::jsonb\")\n            .await?;\n\n        let value: &JsonRawValue = row.try_get(0)?;\n        assert_eq!(value.get(), \"{\\\"hello\\\": \\\"world\\\"}\");\n\n        let value: Box<JsonRawValue> = row.try_get(0)?;\n        assert_eq!(value.get(), \"{\\\"hello\\\": \\\"world\\\"}\");\n\n        // prepared, binary API\n        let row: PgRow = conn\n            .fetch_one(sqlx::query(\"SELECT '{\\\"hello\\\": \\\"world\\\"}'::jsonb\"))\n            .await?;\n\n        let value: &JsonRawValue = row.try_get(0)?;\n        assert_eq!(value.get(), \"{\\\"hello\\\": \\\"world\\\"}\");\n\n        let value: Box<JsonRawValue> = row.try_get(0)?;\n        assert_eq!(value.get(), \"{\\\"hello\\\": \\\"world\\\"}\");\n\n        Ok(())\n    }\n}\n\n#[cfg(feature = \"bigdecimal\")]\ntest_type!(bigdecimal<sqlx::types::BigDecimal>(Postgres,\n\n    // https://github.com/launchbadge/sqlx/issues/283\n    \"0::numeric\" == \"0\".parse::<sqlx::types::BigDecimal>().unwrap(),\n\n    \"1::numeric\" == \"1\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"10000::numeric\" == \"10000\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.1::numeric\" == \"0.1\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.01::numeric\" == \"0.01\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.012::numeric\" == \"0.012\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.0123::numeric\" == \"0.0123\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.01234::numeric\" == \"0.01234\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.012345::numeric\" == \"0.012345\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.0123456::numeric\" == \"0.0123456\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.01234567::numeric\" == \"0.01234567\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.012345678::numeric\" == \"0.012345678\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.0123456789::numeric\" == \"0.0123456789\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.002::numeric\" == \"0.002\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.0002::numeric\" == \"0.0002\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.00002::numeric\" == \"0.00002\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.000002::numeric\" == \"0.000002\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.0000002::numeric\" == \"0.0000002\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"0.00000002::numeric\" == \"0.00000002\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"12.34::numeric\" == \"12.34\".parse::<sqlx::types::BigDecimal>().unwrap(),\n    \"12345.6789::numeric\" == \"12345.6789\".parse::<sqlx::types::BigDecimal>().unwrap(),\n));\n\n#[cfg(feature = \"bigdecimal\")]\ntest_type!(numrange_bigdecimal<PgRange<sqlx::types::BigDecimal>>(Postgres,\n    \"'(1.3,2.4)'::numrange\" == PgRange::from(\n        (Bound::Excluded(\"1.3\".parse::<sqlx::types::BigDecimal>().unwrap()),\n         Bound::Excluded(\"2.4\".parse::<sqlx::types::BigDecimal>().unwrap())))\n));\n\n#[cfg(not(postgres = \"13\"))]\ntest_type!(cube<sqlx::postgres::types::PgCube>(Postgres,\n    \"cube(2)\" == sqlx::postgres::types::PgCube::Point(2.),\n    \"cube(2.1)\" == sqlx::postgres::types::PgCube::Point(2.1),\n    \"cube(2,3)\" == sqlx::postgres::types::PgCube::OneDimensionInterval(2., 3.),\n    \"cube(2.2,-3.4)\" == sqlx::postgres::types::PgCube::OneDimensionInterval(2.2, -3.4),\n    \"cube(array[2,3])\" == sqlx::postgres::types::PgCube::ZeroVolume(vec![2., 3.]),\n    \"cube(array[2,3],array[4,5])\" == sqlx::postgres::types::PgCube::MultiDimension(vec![vec![2.,3.],vec![4.,5.]]),\n    \"cube(array[2,3,4],array[4,5,6])\" == sqlx::postgres::types::PgCube::MultiDimension(vec![vec![2.,3.,4.],vec![4.,5.,6.]]),\n));\n\n#[cfg(not(postgres = \"13\"))]\ntest_type!(_cube<Vec<sqlx::postgres::types::PgCube>>(Postgres,\n    \"array[cube(2),cube(2)]\" == vec![sqlx::postgres::types::PgCube::Point(2.), sqlx::postgres::types::PgCube::Point(2.)],\n    \"array[cube(2.2,-3.4)]\" == vec![sqlx::postgres::types::PgCube::OneDimensionInterval(2.2, -3.4)],\n));\n\ntest_type!(point<sqlx::postgres::types::PgPoint>(Postgres,\n    \"point(2.2,-3.4)\" ~= sqlx::postgres::types::PgPoint { x: 2.2, y:-3.4 },\n));\n\ntest_type!(_point<Vec<sqlx::postgres::types::PgPoint>>(Postgres,\n    \"array[point(2,3),point(2.1,3.4)]\" @= vec![sqlx::postgres::types::PgPoint { x:2., y: 3. }, sqlx::postgres::types::PgPoint { x:2.1, y: 3.4 }],\n    \"array[point(2.2,-3.4)]\" @= vec![sqlx::postgres::types::PgPoint { x: 2.2, y: -3.4 }],\n));\n\ntest_type!(line<sqlx::postgres::types::PgLine>(Postgres,\n    \"line('{1.1, -2.2, 3.3}')\" == sqlx::postgres::types::PgLine { a: 1.1, b:-2.2, c: 3.3 },\n    \"line('((0.0, 0.0), (1.0,1.0))')\" == sqlx::postgres::types::PgLine { a: 1., b: -1., c: 0. },\n));\n\ntest_type!(lseg<sqlx::postgres::types::PgLSeg>(Postgres,\n    \"lseg('((1.0, 2.0), (3.0,4.0))')\" == sqlx::postgres::types::PgLSeg { start_x: 1., start_y: 2., end_x: 3. , end_y: 4.},\n));\n\ntest_type!(box<sqlx::postgres::types::PgBox>(Postgres,\n    \"box('((1.0, 2.0), (3.0,4.0))')\" == sqlx::postgres::types::PgBox { upper_right_x: 3., upper_right_y: 4., lower_left_x: 1. , lower_left_y: 2.},\n));\n\ntest_type!(_box<Vec<sqlx::postgres::types::PgBox>>(Postgres,\n    \"array[box('1,2,3,4'),box('((1.1, 2.2), (3.3, 4.4))')]\" @= vec![sqlx::postgres::types::PgBox { upper_right_x: 3., upper_right_y: 4., lower_left_x: 1., lower_left_y: 2. }, sqlx::postgres::types::PgBox { upper_right_x: 3.3, upper_right_y: 4.4, lower_left_x: 1.1, lower_left_y: 2.2 }],\n));\n\ntest_type!(path<sqlx::postgres::types::PgPath>(Postgres,\n    \"path('((1.0, 2.0), (3.0,4.0))')\" == sqlx::postgres::types::PgPath { closed: true, points: vec![ sqlx::postgres::types::PgPoint { x: 1., y: 2. }, sqlx::postgres::types::PgPoint { x: 3. , y: 4. } ]},\n    \"path('[(1.0, 2.0), (3.0,4.0)]')\" == sqlx::postgres::types::PgPath { closed: false, points: vec![ sqlx::postgres::types::PgPoint { x: 1., y: 2. }, sqlx::postgres::types::PgPoint { x: 3. , y: 4. } ]},\n));\n\ntest_type!(polygon<sqlx::postgres::types::PgPolygon>(Postgres,\n    \"polygon('((-2,-3),(-1,-3),(-1,-1),(1,1),(1,3),(2,3),(2,-3),(1,-3),(1,0),(-1,0),(-1,-2),(-2,-2))')\" ~= sqlx::postgres::types::PgPolygon {  points: vec![\n            sqlx::postgres::types::PgPoint { x: -2., y: -3. }, sqlx::postgres::types::PgPoint { x: -1., y: -3. }, sqlx::postgres::types::PgPoint { x: -1., y: -1. }, sqlx::postgres::types::PgPoint { x: 1., y: 1. },\n            sqlx::postgres::types::PgPoint { x: 1., y: 3. },   sqlx::postgres::types::PgPoint { x: 2., y: 3. },   sqlx::postgres::types::PgPoint { x: 2., y: -3. },  sqlx::postgres::types::PgPoint { x: 1., y: -3. },\n            sqlx::postgres::types::PgPoint { x: 1., y: 0. },   sqlx::postgres::types::PgPoint { x: -1., y: 0. },  sqlx::postgres::types::PgPoint { x: -1., y: -2. }, sqlx::postgres::types::PgPoint { x: -2., y: -2. },\n    ]},\n));\n\ntest_type!(circle<sqlx::postgres::types::PgCircle>(Postgres,\n    \"circle('<(1.1, -2.2), 3.3>')\" ~= sqlx::postgres::types::PgCircle { x: 1.1, y:-2.2, radius: 3.3 },\n    \"circle('((1.1, -2.2), 3.3)')\" ~= sqlx::postgres::types::PgCircle { x: 1.1, y:-2.2, radius: 3.3 },\n    \"circle('(1.1, -2.2), 3.3')\" ~= sqlx::postgres::types::PgCircle { x: 1.1, y:-2.2, radius: 3.3 },\n    \"circle('1.1, -2.2, 3.3')\" ~= sqlx::postgres::types::PgCircle { x: 1.1, y:-2.2, radius: 3.3 },\n));\n\n#[cfg(feature = \"rust_decimal\")]\ntest_type!(decimal<sqlx::types::Decimal>(Postgres,\n    \"0::numeric\" == sqlx::types::Decimal::from_str(\"0\").unwrap(),\n    \"1::numeric\" == sqlx::types::Decimal::from_str(\"1\").unwrap(),\n    \"10000::numeric\" == sqlx::types::Decimal::from_str(\"10000\").unwrap(),\n    \"0.1::numeric\" == sqlx::types::Decimal::from_str(\"0.1\").unwrap(),\n    \"0.01234::numeric\" == sqlx::types::Decimal::from_str(\"0.01234\").unwrap(),\n    \"12.34::numeric\" == sqlx::types::Decimal::from_str(\"12.34\").unwrap(),\n    \"12345.6789::numeric\" == sqlx::types::Decimal::from_str(\"12345.6789\").unwrap(),\n    // https://github.com/launchbadge/sqlx/issues/666#issuecomment-683872154\n    \"17.905625985174584660842500258::numeric\" == sqlx::types::Decimal::from_str(\"17.905625985174584660842500258\").unwrap(),\n    \"-17.905625985174584660842500258::numeric\" == sqlx::types::Decimal::from_str(\"-17.905625985174584660842500258\").unwrap(),\n));\n\n#[cfg(feature = \"rust_decimal\")]\ntest_type!(numrange_decimal<PgRange<sqlx::types::Decimal>>(Postgres,\n    \"'(1.3,2.4)'::numrange\" == PgRange::from(\n        (Bound::Excluded(sqlx::types::Decimal::from_str(\"1.3\").unwrap()),\n         Bound::Excluded(sqlx::types::Decimal::from_str(\"2.4\").unwrap()))),\n));\n\nconst EXC2: Bound<i32> = Bound::Excluded(2);\nconst EXC3: Bound<i32> = Bound::Excluded(3);\nconst INC1: Bound<i32> = Bound::Included(1);\nconst INC2: Bound<i32> = Bound::Included(2);\nconst UNB: Bound<i32> = Bound::Unbounded;\n\ntest_type!(int4range<PgRange<i32>>(Postgres,\n    \"'(,)'::int4range\" == PgRange::from((UNB, UNB)),\n    \"'(,]'::int4range\" == PgRange::from((UNB, UNB)),\n    \"'(,2)'::int4range\" == PgRange::from((UNB, EXC2)),\n    \"'(,2]'::int4range\" == PgRange::from((UNB, EXC3)),\n    \"'(1,)'::int4range\" == PgRange::from((INC2, UNB)),\n    \"'(1,]'::int4range\" == PgRange::from((INC2, UNB)),\n    \"'(1,2]'::int4range\" == PgRange::from((INC2, EXC3)),\n    \"'[,)'::int4range\" == PgRange::from((UNB, UNB)),\n    \"'[,]'::int4range\" == PgRange::from((UNB, UNB)),\n    \"'[,2)'::int4range\" == PgRange::from((UNB, EXC2)),\n    \"'[,2]'::int4range\" == PgRange::from((UNB, EXC3)),\n    \"'[1,)'::int4range\" == PgRange::from((INC1, UNB)),\n    \"'[1,]'::int4range\" == PgRange::from((INC1, UNB)),\n    \"'[1,2)'::int4range\" == PgRange::from((INC1, EXC2)),\n    \"'[1,2]'::int4range\" == PgRange::from((INC1, EXC3)),\n));\n\ntest_prepared_type!(interval<PgInterval>(\n    Postgres,\n    \"INTERVAL '1h'\"\n        == PgInterval {\n            months: 0,\n            days: 0,\n            microseconds: 3_600_000_000\n        },\n    \"INTERVAL '-1 hours'\"\n        == PgInterval {\n            months: 0,\n            days: 0,\n            microseconds: -3_600_000_000\n        },\n    \"INTERVAL '3 months 12 days 1h 15 minutes 10 second '\"\n        == PgInterval {\n            months: 3,\n            days: 12,\n            microseconds: (3_600 + 15 * 60 + 10) * 1_000_000\n        },\n    \"INTERVAL '03:10:20.116100'\"\n        == PgInterval {\n            months: 0,\n            days: 0,\n            microseconds: (3 * 3_600 + 10 * 60 + 20) * 1_000_000 + 116100\n        },\n));\n\ntest_prepared_type!(money<PgMoney>(Postgres, \"123.45::money\" == PgMoney(12345)));\n\ntest_prepared_type!(money_vec<Vec<PgMoney>>(Postgres,\n    \"array[123.45,420.00,666.66]::money[]\" == vec![PgMoney(12345), PgMoney(42000), PgMoney(66666)],\n));\n\ntest_prepared_type!(citext_array<Vec<PgCiText>>(Postgres,\n    \"array['one','two','three']::citext[]\" == vec![\n        PgCiText(\"one\".to_string()),\n        PgCiText(\"two\".to_string()),\n        PgCiText(\"three\".to_string()),\n    ],\n));\n\ntest_type!(ltree<sqlx::postgres::types::PgLTree>(Postgres,\n    \"'Foo.Bar.Baz.Quux'::ltree\" == sqlx::postgres::types::PgLTree::from_str(\"Foo.Bar.Baz.Quux\").unwrap(),\n    \"'Alpha.Beta.Delta.Gamma'::ltree\" == sqlx::postgres::types::PgLTree::try_from_iter([\"Alpha\", \"Beta\", \"Delta\", \"Gamma\"]).unwrap(),\n));\n\ntest_type!(ltree_vec<Vec<sqlx::postgres::types::PgLTree>>(Postgres,\n    \"array['Foo.Bar.Baz.Quux', 'Alpha.Beta.Delta.Gamma']::ltree[]\" ==\n        vec![\n            sqlx::postgres::types::PgLTree::from_str(\"Foo.Bar.Baz.Quux\").unwrap(),\n            sqlx::postgres::types::PgLTree::try_from_iter([\"Alpha\", \"Beta\", \"Delta\", \"Gamma\"]).unwrap()\n        ]\n));\n\n#[derive(sqlx::Type, Debug, PartialEq)]\n#[sqlx(type_name = \"positive_int\")]\nstruct PositiveInt(i32);\n\n#[derive(sqlx::Type, Debug, PartialEq)]\n#[sqlx(type_name = \"percentage\")]\nstruct Percentage(PositiveInt);\n\n#[derive(sqlx::Type, Debug, PartialEq)]\nstruct Person {\n    id: i32,\n    age: PositiveInt,\n    percent: Percentage,\n}\n\ntest_type!(nested_domain_types_1<Person>(Postgres,\n    \"ROW(1, 21::positive_int, 50::percentage)::person\" == Person { id: 1, age: PositiveInt(21), percent: Percentage(PositiveInt(50)) })\n);\n\ntest_type!(domain_type_array_1<Vec<PositiveInt>>(Postgres,\n    \"ARRAY[1, 50, 1000]::positive_int[]\" == vec![\n        PositiveInt(1),\n        PositiveInt(50),\n        PositiveInt(1000),\n    ],\n));\n\ntest_type!(domain_type_array_2<Vec<Percentage>>(Postgres,\n    \"ARRAY[4, 66, 100]::percentage[]\" == vec![\n        Percentage(PositiveInt(4)),\n        Percentage(PositiveInt(66)),\n        Percentage(PositiveInt(100))\n    ],\n));\n\n#[derive(sqlx::Type, Debug, PartialEq)]\n#[sqlx(type_name = \"leaf_composite\")]\nstruct LeafComposite {\n    prim: i32,\n}\n\n#[derive(sqlx::Type, Debug, PartialEq)]\n#[sqlx(type_name = \"domain\")]\nstruct Domain(LeafComposite);\n\n#[derive(sqlx::Type, Debug, PartialEq)]\n#[sqlx(type_name = \"root_composite\")]\nstruct RootComposite {\n    domain: Domain,\n}\n\ntest_type!(nested_domain_types_2<RootComposite>(Postgres,\n    \"ROW(ROW(1))::root_composite\" == RootComposite { domain: Domain(LeafComposite { prim: 1 }) })\n);\n\ntest_type!(domain_type_array_3<Vec<Domain>>(Postgres,\n    \"ARRAY[ROW(50), ROW(1), ROW(1000)]::domain[]\" == vec![\n        Domain(LeafComposite { prim: 50 }),\n        Domain(LeafComposite { prim: 1 }),\n        Domain(LeafComposite { prim: 1000 }),\n    ]\n));\n\ntest_type!(test_arc<Arc<i32>>(Postgres, \"1::INT4\" == Arc::new(1i32)));\ntest_type!(test_cow<Cow<'_, i32>>(Postgres, \"1::INT4\" == Cow::<i32>::Owned(1i32)));\ntest_type!(test_box<Box<i32>>(Postgres, \"1::INT4\" == Box::new(1i32)));\ntest_type!(test_rc<Rc<i32>>(Postgres, \"1::INT4\" == Rc::new(1i32)));\n\ntest_type!(test_box_str<Box<str>>(Postgres, \"'John'::TEXT\" == Box::<str>::from(\"John\")));\ntest_type!(test_cow_str<Cow<'_, str>>(Postgres, \"'Phil'::TEXT\" == Cow::<'static, str>::from(\"Phil\")));\ntest_type!(test_arc_str<Arc<str>>(Postgres, \"'1234'::TEXT\" == Arc::<str>::from(\"1234\")));\ntest_type!(test_rc_str<Rc<str>>(Postgres, \"'5678'::TEXT\" == Rc::<str>::from(\"5678\")));\n\ntest_prepared_type!(test_box_slice<Box<[u8]>>(Postgres, \"'\\\\x01020304'::BYTEA\" == Box::<[u8]>::from([1,2,3,4])));\ntest_prepared_type!(test_cow_slice<Cow<'_, [u8]>>(Postgres, \"'\\\\x01020304'::BYTEA\" == Cow::<'static, [u8]>::from(&[1,2,3,4])));\ntest_prepared_type!(test_arc_slice<Arc<[u8]>>(Postgres, \"'\\\\x01020304'::BYTEA\" == Arc::<[u8]>::from([1,2,3,4])));\ntest_prepared_type!(test_rc_slice<Rc<[u8]>>(Postgres, \"'\\\\x01020304'::BYTEA\" == Rc::<[u8]>::from([1,2,3,4])));\n\n#[sqlx_macros::test]\nasync fn test_text_adapter() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n    struct Login {\n        user_id: i32,\n        socket_addr: Text<SocketAddr>,\n        #[cfg(feature = \"time\")]\n        login_at: time::OffsetDateTime,\n    }\n\n    let mut conn = new::<Postgres>().await?;\n\n    conn.execute(\n        r#\"\nCREATE TEMPORARY TABLE user_login (\n    user_id INT PRIMARY KEY,\n    socket_addr TEXT NOT NULL,\n    login_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n);\n    \"#,\n    )\n    .await?;\n\n    let user_id = 1234;\n    let socket_addr: SocketAddr = \"198.51.100.47:31790\".parse().unwrap();\n\n    sqlx::query(\"INSERT INTO user_login (user_id, socket_addr) VALUES ($1, $2)\")\n        .bind(user_id)\n        .bind(Text(socket_addr))\n        .execute(&mut conn)\n        .await?;\n\n    let last_login: Login =\n        sqlx::query_as(\"SELECT * FROM user_login ORDER BY login_at DESC LIMIT 1\")\n            .fetch_one(&mut conn)\n            .await?;\n\n    assert_eq!(last_login.user_id, user_id);\n    assert_eq!(*last_login.socket_addr, socket_addr);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/.gitignore",
    "content": "sqlite.test.db\n\n"
  },
  {
    "path": "tests/sqlite/any.rs",
    "content": "use sqlx::Any;\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_encodes_bool_with_any() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n    let mut conn = new::<Any>().await?;\n\n    let res = sqlx::query(\"INSERT INTO accounts (name, is_active) VALUES (?, ?)\")\n        .bind(\"Harrison Ford\")\n        .bind(true)\n        .execute(&mut conn)\n        .await\n        .expect(\"failed to encode bool\");\n    assert_eq!(res.rows_affected(), 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn issue_3179() -> anyhow::Result<()> {\n    sqlx::any::install_default_drivers();\n\n    let mut conn = new::<Any>().await?;\n\n    // 4294967297 = 2^32\n    let number: i64 = sqlx::query_scalar(\"SELECT 4294967296\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    // Previously, the decoding would use `i32` as an intermediate which would overflow to 0.\n    assert_eq!(number, 4294967296);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/derives.rs",
    "content": "use sqlx::Sqlite;\nuse sqlx_test::test_type;\n\n#[derive(Debug, PartialEq, sqlx::Type)]\n#[repr(u32)]\nenum Origin {\n    Foo = 1,\n    Bar = 2,\n}\n\ntest_type!(origin_enum<Origin>(Sqlite,\n    \"1\" == Origin::Foo,\n    \"2\" == Origin::Bar,\n));\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct TransparentTuple(i64);\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct TransparentNamed {\n    field: i64,\n}\n\ntest_type!(transparent_tuple<TransparentTuple>(Sqlite,\n    \"0\" == TransparentTuple(0),\n    \"23523\" == TransparentTuple(23523)\n));\n\ntest_type!(transparent_named<TransparentNamed>(Sqlite,\n    \"0\" == TransparentNamed { field: 0 },\n    \"23523\" == TransparentNamed { field: 23523 },\n));\n"
  },
  {
    "path": "tests/sqlite/describe.rs",
    "content": "use sqlx::error::DatabaseError;\nuse sqlx::sqlite::{SqliteConnectOptions, SqliteError};\nuse sqlx::TypeInfo;\nuse sqlx::{sqlite::Sqlite, Column, Executor};\nuse sqlx::{ConnectOptions, SqlSafeStr};\nuse sqlx_test::new;\nuse std::env;\n\n#[sqlx_macros::test]\nasync fn it_describes_simple() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let info = conn.describe(\"SELECT * FROM tweet\".into_sql_str()).await?;\n    let columns = info.columns();\n\n    assert_eq!(columns[0].name(), \"id\");\n    assert_eq!(columns[1].name(), \"text\");\n    assert_eq!(columns[2].name(), \"is_sent\");\n    assert_eq!(columns[3].name(), \"owner_id\");\n\n    assert_eq!(columns[0].ordinal(), 0);\n    assert_eq!(columns[1].ordinal(), 1);\n    assert_eq!(columns[2].ordinal(), 2);\n    assert_eq!(columns[3].ordinal(), 3);\n\n    assert_eq!(info.nullable(0), Some(false));\n    assert_eq!(info.nullable(1), Some(false));\n    assert_eq!(info.nullable(2), Some(false));\n    assert_eq!(info.nullable(3), Some(true)); // owner_id\n\n    assert_eq!(columns[0].type_info().name(), \"INTEGER\");\n    assert_eq!(columns[1].type_info().name(), \"TEXT\");\n    assert_eq!(columns[2].type_info().name(), \"BOOLEAN\");\n    assert_eq!(columns[3].type_info().name(), \"INTEGER\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_variables() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    // without any context, we resolve to NULL\n    let info = conn.describe(\"SELECT ?1\".into_sql_str()).await?;\n\n    assert_eq!(info.columns()[0].type_info().name(), \"NULL\");\n    assert_eq!(info.nullable(0), Some(true)); // nothing prevents the value from being bound to null\n\n    // context can be provided by using CAST(_ as _)\n    let info = conn\n        .describe(\"SELECT CAST(?1 AS REAL)\".into_sql_str())\n        .await?;\n\n    assert_eq!(info.columns()[0].type_info().name(), \"REAL\");\n    assert_eq!(info.nullable(0), Some(true)); // nothing prevents the value from being bound to null\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_expression() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"SELECT 1 + 10, 5.12 * 2, 'Hello', x'deadbeef', null\".into_sql_str())\n        .await?;\n\n    let columns = d.columns();\n\n    assert_eq!(columns[0].type_info().name(), \"INTEGER\");\n    assert_eq!(columns[0].name(), \"1 + 10\");\n    assert_eq!(d.nullable(0), Some(false)); // literal constant\n\n    assert_eq!(columns[1].type_info().name(), \"REAL\");\n    assert_eq!(columns[1].name(), \"5.12 * 2\");\n    assert_eq!(d.nullable(1), Some(false)); // literal constant\n\n    assert_eq!(columns[2].type_info().name(), \"TEXT\");\n    assert_eq!(columns[2].name(), \"'Hello'\");\n    assert_eq!(d.nullable(2), Some(false)); // literal constant\n\n    assert_eq!(columns[3].type_info().name(), \"BLOB\");\n    assert_eq!(columns[3].name(), \"x'deadbeef'\");\n    assert_eq!(d.nullable(3), Some(false)); // literal constant\n\n    assert_eq!(columns[4].type_info().name(), \"NULL\");\n    assert_eq!(columns[4].name(), \"null\");\n    assert_eq!(d.nullable(4), Some(true)); // literal null\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_temporary_table() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    conn.execute(\n        \"CREATE TEMPORARY TABLE IF NOT EXISTS empty_all_types_and_nulls(\n        i1 integer NULL,\n        r1 real NULL,\n        t1 text NULL,\n        b1 blob NULL,\n        i2 INTEGER NOT NULL,\n        r2 REAL NOT NULL,\n        t2 TEXT NOT NULL,\n        b2 BLOB NOT NULL\n        )\",\n    )\n    .await?;\n\n    let d = conn\n        .describe(\"SELECT * FROM empty_all_types_and_nulls\".into_sql_str())\n        .await?;\n    assert_eq!(d.columns().len(), 8);\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    assert_eq!(d.column(1).type_info().name(), \"REAL\");\n    assert_eq!(d.nullable(1), Some(true));\n\n    assert_eq!(d.column(2).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(2), Some(true));\n\n    assert_eq!(d.column(3).type_info().name(), \"BLOB\");\n    assert_eq!(d.nullable(3), Some(true));\n\n    assert_eq!(d.column(4).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(4), Some(false));\n\n    assert_eq!(d.column(5).type_info().name(), \"REAL\");\n    assert_eq!(d.nullable(5), Some(false));\n\n    assert_eq!(d.column(6).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(6), Some(false));\n\n    assert_eq!(d.column(7).type_info().name(), \"BLOB\");\n    assert_eq!(d.nullable(7), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_expression_from_empty_table() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    conn.execute(\"CREATE TEMP TABLE _temp_empty ( name TEXT NOT NULL, a INT )\")\n        .await?;\n\n    let d = conn\n        .describe(\"SELECT COUNT(*), a + 1, name, 5.12, 'Hello' FROM _temp_empty\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns()[0].type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false)); // COUNT(*)\n\n    assert_eq!(d.columns()[1].type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(1), Some(true)); // `a+1` is nullable, because a is nullable\n\n    assert_eq!(d.columns()[2].type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(2), Some(true)); // `name` is not nullable, but the query can be null due to zero rows\n\n    assert_eq!(d.columns()[3].type_info().name(), \"REAL\");\n    assert_eq!(d.nullable(3), Some(false)); // literal constant\n\n    assert_eq!(d.columns()[4].type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(4), Some(false)); // literal constant\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_expression_from_empty_table_with_star() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    conn.execute(\"CREATE TEMP TABLE _temp_empty ( name TEXT, a INT )\")\n        .await?;\n\n    let d = conn\n        .describe(\"SELECT *, 5, 'Hello' FROM _temp_empty\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns()[0].type_info().name(), \"TEXT\");\n    assert_eq!(d.columns()[1].type_info().name(), \"INTEGER\");\n    assert_eq!(d.columns()[2].type_info().name(), \"INTEGER\");\n    assert_eq!(d.columns()[3].type_info().name(), \"TEXT\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_insert() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"INSERT INTO tweet (id, text) VALUES (2, 'Hello')\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 0);\n\n    let d = conn\n        .describe(\n            \"INSERT INTO tweet (id, text) VALUES (2, 'Hello'); SELECT last_insert_rowid();\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.columns().len(), 1);\n    assert_eq!(d.columns()[0].type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_insert_with_read_only() -> anyhow::Result<()> {\n    sqlx_test::setup_if_needed();\n\n    let mut options: SqliteConnectOptions = env::var(\"DATABASE_URL\")?.parse().unwrap();\n    options = options.read_only(true);\n\n    let mut conn = options.connect().await?;\n\n    let d = conn\n        .describe(\"INSERT INTO tweet (id, text) VALUES (2, 'Hello')\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 0);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_insert_with_returning() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"INSERT INTO tweet (id, text) VALUES (2, 'Hello') RETURNING *\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 4);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.column(1).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(1), Some(false));\n\n    let d = conn\n        .describe(\n            \"INSERT INTO accounts (name, is_active) VALUES ('a', true) RETURNING id\".into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.columns().len(), 1);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_bound_columns_non_null() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let d = conn\n        .describe(\"INSERT INTO tweet (id, text) VALUES ($1, $2) returning *\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 4);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.column(1).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(1), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_update_with_returning() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"UPDATE accounts SET is_active=true WHERE name=?1 RETURNING id\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 1);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"UPDATE accounts SET is_active=true WHERE id=?1 RETURNING *\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 3);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.column(1).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(1), Some(false));\n    assert_eq!(d.column(2).type_info().name(), \"BOOLEAN\");\n    //assert_eq!(d.nullable(2), Some(false)); //query analysis is allowed to notice that it is always set to true by the update\n\n    let d = conn\n        .describe(\"UPDATE accounts SET is_active=true WHERE id=?1 RETURNING id\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 1);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_delete_with_returning() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"DELETE FROM accounts WHERE name=?1 RETURNING id\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.columns().len(), 1);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_bad_statement() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let err = conn\n        .describe(\"SELECT 1 FROM not_found\".into_sql_str())\n        .await\n        .unwrap_err();\n    let err = err\n        .as_database_error()\n        .unwrap()\n        .downcast_ref::<SqliteError>();\n\n    assert_eq!(err.message(), \"no such table: not_found\");\n    assert_eq!(err.code().as_deref(), Some(\"1\"));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_left_join() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"select accounts.id from accounts\".into_sql_str())\n        .await?;\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\n            \"select tweet.id from accounts left join tweet on owner_id = accounts.id\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\n            \"select tweet.id, accounts.id from accounts left join tweet on owner_id = accounts.id\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    assert_eq!(d.column(1).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(1), Some(false));\n\n    let d = conn\n        .describe(\n            \"select tweet.id, accounts.id from accounts inner join tweet on owner_id = accounts.id\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    assert_eq!(d.column(1).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(1), Some(false));\n\n    let d = conn\n        .describe(\n            \"select tweet.id, accounts.id from accounts left join tweet on tweet.id = accounts.id\"\n                .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    assert_eq!(d.column(1).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(1), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_group_by() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"select id from accounts group by id\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"SELECT name from accounts GROUP BY 1 LIMIT -1 OFFSET 1\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"SELECT sum(id), sum(is_sent) from tweet GROUP BY owner_id\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n    assert_eq!(d.column(1).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(1), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_ungrouped_aggregate() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"select count(1) from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"SELECT sum(is_sent) from tweet\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"SELECT coalesce(sum(is_sent),0) from tweet\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_literal_subquery() -> anyhow::Result<()> {\n    async fn assert_literal_described(\n        conn: &mut sqlx::SqliteConnection,\n        query: &'static str,\n    ) -> anyhow::Result<()> {\n        let info = conn.describe(query.into_sql_str()).await?;\n\n        assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n        assert_eq!(info.nullable(0), Some(false), \"{query}\");\n        assert_eq!(info.column(1).type_info().name(), \"NULL\", \"{query}\");\n        assert_eq!(info.nullable(1), Some(true), \"{query}\");\n\n        Ok(())\n    }\n\n    let mut conn = new::<Sqlite>().await?;\n    assert_literal_described(&mut conn, \"SELECT 'a', NULL\").await?;\n    assert_literal_described(&mut conn, \"SELECT * FROM (SELECT 'a', NULL)\").await?;\n    assert_literal_described(\n        &mut conn,\n        \"WITH cte AS (SELECT 'a', NULL) SELECT * FROM cte\",\n    )\n    .await?;\n    assert_literal_described(\n        &mut conn,\n        \"WITH cte AS MATERIALIZED (SELECT 'a', NULL) SELECT * FROM cte\",\n    )\n    .await?;\n    assert_literal_described(\n        &mut conn,\n        \"WITH RECURSIVE cte(a,b) AS (SELECT 'a', NULL UNION ALL SELECT a||a, NULL FROM cte WHERE length(a)<3) SELECT * FROM cte\",\n    )\n    .await?;\n\n    Ok(())\n}\n\nasync fn assert_tweet_described(\n    conn: &mut sqlx::SqliteConnection,\n    query: &'static str,\n) -> anyhow::Result<()> {\n    let info = conn.describe(query.into_sql_str()).await?;\n    let columns = info.columns();\n\n    assert_eq!(columns[0].name(), \"id\", \"{query}\");\n    assert_eq!(columns[1].name(), \"text\", \"{query}\");\n    assert_eq!(columns[2].name(), \"is_sent\", \"{query}\");\n    assert_eq!(columns[3].name(), \"owner_id\", \"{query}\");\n\n    assert_eq!(columns[0].ordinal(), 0, \"{query}\");\n    assert_eq!(columns[1].ordinal(), 1, \"{query}\");\n    assert_eq!(columns[2].ordinal(), 2, \"{query}\");\n    assert_eq!(columns[3].ordinal(), 3, \"{query}\");\n\n    assert_eq!(info.nullable(0), Some(false), \"{query}\");\n    assert_eq!(info.nullable(1), Some(false), \"{query}\");\n    assert_eq!(info.nullable(2), Some(false), \"{query}\");\n    assert_eq!(info.nullable(3), Some(true), \"{query}\");\n\n    assert_eq!(columns[0].type_info().name(), \"INTEGER\", \"{query}\");\n    assert_eq!(columns[1].type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(columns[2].type_info().name(), \"BOOLEAN\", \"{query}\");\n    assert_eq!(columns[3].type_info().name(), \"INTEGER\", \"{query}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_table_subquery() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    assert_tweet_described(&mut conn, \"SELECT * FROM tweet\").await?;\n    assert_tweet_described(&mut conn, \"SELECT * FROM (SELECT * FROM tweet)\").await?;\n    assert_tweet_described(\n        &mut conn,\n        \"WITH cte AS (SELECT * FROM tweet) SELECT * FROM cte\",\n    )\n    .await?;\n    assert_tweet_described(\n        &mut conn,\n        \"WITH cte AS MATERIALIZED (SELECT * FROM tweet) SELECT * FROM cte\",\n    )\n    .await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_table_order_by() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    assert_tweet_described(&mut conn, \"SELECT * FROM tweet ORDER BY id\").await?;\n    assert_tweet_described(&mut conn, \"SELECT * FROM tweet ORDER BY id NULLS LAST\").await?;\n    assert_tweet_described(\n        &mut conn,\n        \"SELECT * FROM tweet ORDER BY owner_id DESC, text ASC\",\n    )\n    .await?;\n\n    async fn assert_literal_order_by_described(\n        conn: &mut sqlx::SqliteConnection,\n        query: &'static str,\n    ) -> anyhow::Result<()> {\n        let info = conn.describe(query.into_sql_str()).await?;\n\n        assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n        assert_eq!(info.nullable(0), Some(false), \"{query}\");\n        assert_eq!(info.column(1).type_info().name(), \"TEXT\", \"{query}\");\n        assert_eq!(info.nullable(1), Some(false), \"{query}\");\n\n        Ok(())\n    }\n\n    assert_literal_order_by_described(&mut conn, \"SELECT 'a', text FROM tweet ORDER BY id\").await?;\n    assert_literal_order_by_described(\n        &mut conn,\n        \"SELECT 'a', text FROM tweet ORDER BY id NULLS LAST\",\n    )\n    .await?;\n    assert_literal_order_by_described(&mut conn, \"SELECT 'a', text FROM tweet ORDER BY text\")\n        .await?;\n    assert_literal_order_by_described(\n        &mut conn,\n        \"SELECT 'a', text FROM tweet ORDER BY text NULLS LAST\",\n    )\n    .await?;\n    assert_literal_order_by_described(\n        &mut conn,\n        \"SELECT 'a', text FROM tweet ORDER BY text DESC NULLS LAST\",\n    )\n    .await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_union() -> anyhow::Result<()> {\n    async fn assert_union_described(\n        conn: &mut sqlx::SqliteConnection,\n        query: &'static str,\n    ) -> anyhow::Result<()> {\n        let info = conn.describe(query.into_sql_str()).await?;\n\n        assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n        assert_eq!(info.nullable(0), Some(false), \"{query}\");\n        assert_eq!(info.column(1).type_info().name(), \"TEXT\", \"{query}\");\n        assert_eq!(info.nullable(1), Some(true), \"{query}\");\n        assert_eq!(info.column(2).type_info().name(), \"INTEGER\", \"{query}\");\n        assert_eq!(info.nullable(2), Some(true), \"{query}\");\n        //TODO: mixed type columns not handled correctly\n        //assert_eq!(info.column(3).type_info().name(), \"NULL\", \"{query}\");\n        //assert_eq!(info.nullable(3), Some(false), \"{query}\");\n\n        Ok(())\n    }\n\n    let mut conn = new::<Sqlite>().await?;\n    assert_union_described(\n        &mut conn,\n        \"SELECT 'txt','a',null,'b' UNION ALL SELECT 'int',NULL,1,2 \",\n    )\n    .await?;\n\n    //TODO: insert into temp-table not merging datatype/nullable of all operations - currently keeping last-writer\n    //assert_union_described(&mut conn, \"SELECT 'txt','a',null,'b' UNION SELECT 'int',NULL,1,2 \").await?;\n\n    assert_union_described(\n        &mut conn,\n        \"SELECT 'tweet',text,owner_id id,null from tweet\n        UNION SELECT 'account',name,id,is_active from accounts\n        UNION SELECT 'account',name,id,is_active from accounts_view\n        UNION SELECT 'dummy',null,null,null\n        ORDER BY id\n        \",\n    )\n    .await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_having_group_by() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\n            r#\"\n        WITH tweet_reply_unq as ( --tweets with a single response\n          SELECT tweet_id id\n          FROM tweet_reply\n          GROUP BY tweet_id\n          HAVING COUNT(1) = 1\n        ) \n        SELECT \n          (\n    \t\t  SELECT COUNT(*) \n    \t\t  FROM (\n    \t\t    SELECT NULL\n    \t\t\tFROM tweet\n    \t\t\tJOIN tweet_reply_unq\n    \t\t\t  USING (id)\n                WHERE tweet.owner_id = accounts.id\n              )\n          ) single_reply_count\n        FROM accounts\n        WHERE id = ?1\n        \"#\n            .into_sql_str(),\n        )\n        .await?;\n\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    Ok(())\n}\n\n//documents failures originally found through property testing\n#[sqlx_macros::test]\nasync fn it_describes_strange_queries() -> anyhow::Result<()> {\n    async fn assert_single_column_described(\n        conn: &mut sqlx::SqliteConnection,\n        query: &'static str,\n        typename: &str,\n        nullable: bool,\n    ) -> anyhow::Result<()> {\n        let info = conn.describe(query.into_sql_str()).await?;\n        assert_eq!(info.column(0).type_info().name(), typename, \"{query}\");\n        assert_eq!(info.nullable(0), Some(nullable), \"{query}\");\n\n        Ok(())\n    }\n\n    let mut conn = new::<Sqlite>().await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT true FROM (SELECT true) a ORDER BY true\",\n        \"INTEGER\",\n        false,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"\n    \tSELECT true\n    \tFROM (\n    \t    SELECT 'a'\n    \t)\n    \tCROSS JOIN (\n    \t    SELECT 'b'\n    \t    FROM (SELECT 'c')\n            CROSS JOIN accounts\n            ORDER BY id\n            LIMIT 1\n            )\n    \t\",\n        \"INTEGER\",\n        false,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT true FROM tweet\n            ORDER BY true ASC NULLS LAST\",\n        \"INTEGER\",\n        false,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT true LIMIT -1 OFFSET -1\",\n        \"INTEGER\",\n        false,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT true FROM tweet J LIMIT 10 OFFSET 1000000\",\n        \"INTEGER\",\n        false,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT text\n        FROM (SELECT null)\n        CROSS JOIN (\n            SELECT text\n            FROM tweet \n            GROUP BY text\n        )\n        LIMIT -1 OFFSET -1\",\n        \"TEXT\",\n        false,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT EYH.id,COUNT(EYH.id)\n    \tFROM accounts EYH\",\n        \"INTEGER\",\n        true,\n    )\n    .await?;\n\n    assert_single_column_described(\n        &mut conn,\n        \"SELECT SUM(tweet.text) FROM (SELECT NULL FROM accounts_view LIMIT -1 OFFSET 1) CROSS JOIN tweet\",\n        \"REAL\",\n        true, // null if accounts view has fewer rows than the offset\n    )\n    .await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_func_date() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let query = \"SELECT date();\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(false), \"{query}\");\n\n    let query = \"SELECT date('now');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT date('now', 'start of month');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT date(:datebind);\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_func_time() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let query = \"SELECT time();\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(false), \"{query}\");\n\n    let query = \"SELECT time('now');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT time('now', 'start of month');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT time(:datebind);\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_func_datetime() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let query = \"SELECT datetime();\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(false), \"{query}\");\n\n    let query = \"SELECT datetime('now');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT datetime('now', 'start of month');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT datetime(:datebind);\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_func_julianday() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let query = \"SELECT julianday();\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"REAL\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(false), \"{query}\");\n\n    let query = \"SELECT julianday('now');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"REAL\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT julianday('now', 'start of month');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"REAL\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT julianday(:datebind);\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"REAL\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_func_strftime() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let query = \"SELECT strftime('%s','now');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT strftime('%s', 'now', 'start of month');\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\"); //can't prove that it's not-null yet\n\n    let query = \"SELECT strftime('%s',:datebind);\";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_with_recursive() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let query = \"\n        WITH RECURSIVE schedule(begin_date) AS (\n             SELECT datetime('2022-10-01')\n             WHERE datetime('2022-10-01') < datetime('2022-11-03')\n             UNION ALL\n             SELECT datetime(begin_date,'+1 day')\n             FROM schedule\n             WHERE datetime(begin_date) < datetime(?2)\n         )\n         SELECT\n             begin_date\n         FROM schedule\n         GROUP BY begin_date\n        \";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n\n    let query = \"\n        WITH RECURSIVE schedule(begin_date) AS MATERIALIZED (\n             SELECT datetime('2022-10-01')\n             WHERE datetime('2022-10-01') < datetime('2022-11-03')\n             UNION ALL\n             SELECT datetime(begin_date,'+1 day')\n             FROM schedule\n             WHERE datetime(begin_date) < datetime(?2)\n         )\n         SELECT\n             begin_date\n         FROM schedule\n         GROUP BY begin_date\n        \";\n    let info = conn.describe(query.into_sql_str()).await?;\n    assert_eq!(info.column(0).type_info().name(), \"TEXT\", \"{query}\");\n    assert_eq!(info.nullable(0), Some(true), \"{query}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_describes_analytical_function() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let d = conn\n        .describe(\"select row_number() over () from accounts\".into_sql_str())\n        .await?;\n    dbg!(&d);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select rank() over () from accounts\".into_sql_str())\n        .await?;\n    dbg!(&d);\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select dense_rank() over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select percent_rank() over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"REAL\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select cume_dist() over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"REAL\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select ntile(1) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select lag(id) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select lag(name) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select lead(id) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select lead(name) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select first_value(id) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select first_value(name) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select last_value(id) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(false));\n\n    let d = conn\n        .describe(\"select first_value(name) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"TEXT\");\n    //assert_eq!(d.nullable(0), Some(false)); //this should be null, but it's hard to prove that it will be\n\n    let d = conn\n        .describe(\"select nth_value(id,10) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    let d = conn\n        .describe(\"select nth_value(name,10) over () from accounts\".into_sql_str())\n        .await?;\n    assert_eq!(d.column(0).type_info().name(), \"TEXT\");\n    assert_eq!(d.nullable(0), Some(true));\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/error.rs",
    "content": "use sqlx::{error::ErrorKind, sqlite::Sqlite, Connection, Error};\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn it_fails_with_unique_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"INSERT INTO tweet VALUES (1, 'Foo', true, 1);\")\n        .execute(&mut *tx)\n        .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::UniqueViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_foreign_key_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO tweet_reply (id, tweet_id, text) VALUES (2, 2, 'Reply!');\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::ForeignKeyViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_not_null_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> = sqlx::query(\"INSERT INTO tweet (text) VALUES (null);\")\n        .execute(&mut *tx)\n        .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::NotNullViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_check_violation() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let mut tx = conn.begin().await?;\n\n    let res: Result<_, sqlx::Error> =\n        sqlx::query(\"INSERT INTO products VALUES (1, 'Product 1', 0);\")\n            .execute(&mut *tx)\n            .await;\n    let err = res.unwrap_err();\n\n    let err = err.into_database_error().unwrap();\n\n    assert_eq!(err.kind(), ErrorKind::CheckViolation);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_begin_failed() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let res = conn.begin_with(\"SELECT * FROM tweet\").await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::BeginFailed), \"{err:?}\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_with_invalid_save_point_statement() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let mut txn = conn.begin().await?;\n    let txn_conn = sqlx::Acquire::acquire(&mut txn).await?;\n    let res = txn_conn.begin_with(\"BEGIN\").await;\n\n    let err = res.unwrap_err();\n\n    assert!(matches!(err, Error::InvalidSavePointStatement), \"{err}\");\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/fixtures/comments.sql",
    "content": "insert into comment(comment_id, post_id, user_id, content, created_at)\nvalues (1,\n        1,\n        2,\n        'lol bet ur still bad, 1v1 me',\n        datetime('now', '-50 minutes')),\n       (2,\n        1,\n        1,\n        'you''re on!',\n        datetime('now', '-45 minutes')),\n       (3,\n        2,\n        1,\n        'lol you''re just mad you lost :P',\n        datetime('now', '-15 minutes'));\n"
  },
  {
    "path": "tests/sqlite/fixtures/posts.sql",
    "content": "insert into post(post_id, user_id, content, created_at)\nvalues (1,\n        1,\n        'This new computer is lightning-fast!',\n        datetime('now', '-1 hour')),\n       (2,\n        2,\n        '@alice is a haxxor :(',\n        datetime('now', '-30 minutes'));\n"
  },
  {
    "path": "tests/sqlite/fixtures/users.sql",
    "content": "insert into \"user\"(user_id, username)\nvalues (1, 'alice'), (2, 'bob');\n"
  },
  {
    "path": "tests/sqlite/macros.rs",
    "content": "use sqlx::Sqlite;\nuse sqlx_test::new;\n\n#[sqlx_macros::test]\nasync fn macro_select() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let account = sqlx::query!(\"select id, name, is_active from accounts where id = 1\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(1, account.id);\n    assert_eq!(\"Herp Derpinson\", account.name);\n    assert_eq!(account.is_active, Some(true));\n\n    Ok(())\n}\n\nmacro_rules! gen_macro_select_concats {\n    ($param:literal) => {\n        #[sqlx_macros::test]\n        async fn macro_select_concat_single() -> anyhow::Result<()> {\n            let mut conn = new::<Sqlite>().await?;\n\n            let account = sqlx::query!(\"select \" + $param + \" from accounts where id = 1\")\n                .fetch_one(&mut conn)\n                .await?;\n\n            assert_eq!(1, account.id);\n            assert_eq!(\"Herp Derpinson\", account.name);\n            assert_eq!(account.is_active, Some(true));\n\n            Ok(())\n        }\n    };\n}\n\ngen_macro_select_concats!(\"id, name, is_active\");\n\n#[sqlx_macros::test]\nasync fn macro_select_expression() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let row = sqlx::query!(\"select 10 as _1, 'Hello' as _2\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(10, row._1);\n    assert_eq!(\"Hello\", &*row._2);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn macro_select_partial_expression() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let row = sqlx::query!(\n        \"select 10 as _1, 'Hello' as _2, is_active, name, id + 5 as id_p from accounts where id = 1\"\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(10, row._1);\n    assert_eq!(\"Hello\", &*row._2);\n    assert_eq!(6, row.id_p);\n    assert_eq!(\"Herp Derpinson\", row.name);\n    assert_eq!(row.is_active, Some(true));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn macro_select_bind() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let account = sqlx::query!(\n        \"select id, name, is_active from accounts where id = ?\",\n        1i32\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(1, account.id);\n    assert_eq!(\"Herp Derpinson\", account.name);\n    assert_eq!(account.is_active, Some(true));\n\n    Ok(())\n}\n\n#[derive(Debug)]\nstruct RawAccount {\n    id: i64,\n    name: String,\n    is_active: Option<bool>,\n}\n\n#[sqlx_macros::test]\nasync fn test_query_as_raw() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let account = sqlx::query_as!(RawAccount, \"SELECT id, name, is_active from accounts\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, \"Herp Derpinson\");\n    assert_eq!(account.is_active, Some(true));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_scalar() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let id = sqlx::query_scalar!(\"select 1\").fetch_one(&mut conn).await?;\n    assert_eq!(id, 1i64);\n\n    // invalid column names are ignored\n    let id = sqlx::query_scalar!(r#\"select 1 as \"&foo\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(id, 1i64);\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo!\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n    assert_eq!(id, 1i64);\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo?\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(1i64));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo: MyInt\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1i64));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo?: MyInt\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, Some(MyInt(1i64)));\n\n    let id = sqlx::query_scalar!(r#\"select 1 as \"foo!: MyInt\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1i64));\n\n    let id: MyInt = sqlx::query_scalar!(r#\"select 1 as \"foo: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1i64));\n\n    let id: MyInt = sqlx::query_scalar!(r#\"select 1 as \"foo?: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?\n        // don't hint that it should be `Option<MyInt>`\n        .unwrap();\n\n    assert_eq!(id, MyInt(1i64));\n\n    let id: MyInt = sqlx::query_scalar!(r#\"select 1 as \"foo!: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(id, MyInt(1i64));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn query_by_string() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let string = \"Hello, world!\".to_string();\n    let ref tuple = (\"Hello, world!\".to_string(),);\n\n    let result = sqlx::query!(\n        \"SELECT 'Hello, world!' as string where 'Hello, world!' in (?, ?, ?, ?, ?, ?, ?)\",\n        string, // make sure we don't actually take ownership here\n        &string[..],\n        Some(&string),\n        Some(&string[..]),\n        Option::<String>::None,\n        string.clone(),\n        tuple.0 // make sure we're not trying to move out of a field expression\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(result.string, string);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn macro_select_from_view() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let account = sqlx::query!(\"SELECT id, name, is_active from accounts_view\")\n        .fetch_one(&mut conn)\n        .await?;\n\n    // SQLite tells us the true origin of these columns even through the view\n    assert_eq!(account.id, 1);\n    assert_eq!(account.name, \"Herp Derpinson\");\n    assert_eq!(account.is_active, Some(true));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query!(r#\"select owner_id as `owner_id!` from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.owner_id, 1);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query!(r#\"select text as `text?` from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.text.as_deref(), Some(\"#sqlx is pretty cool!\"));\n\n    Ok(())\n}\n\n#[derive(PartialEq, Eq, Debug, sqlx::Type)]\n#[sqlx(transparent)]\nstruct MyInt(i64);\n\nstruct Record {\n    id: MyInt,\n}\n\nstruct OptionalRecord {\n    id: Option<MyInt>,\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query_as!(Record, r#\"select id as \"id: _\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    // this syntax is also useful for expressions\n    let record = sqlx::query_as!(Record, r#\"select 1 as \"id: _\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    let record = sqlx::query_as!(OptionalRecord, r#\"select owner_id as \"id: _\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query_as!(Record, r#\"select owner_id as \"id!: _\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_wildcard_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query_as!(OptionalRecord, r#\"select id as \"id?: _\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query!(r#\"select id as \"id: MyInt\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    // we can also support this syntax for expressions\n    let record = sqlx::query!(r#\"select 1 as \"id: MyInt\"\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    let record = sqlx::query!(r#\"select owner_id as \"id: MyInt\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_not_null() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query!(r#\"select owner_id as \"id!: MyInt\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, MyInt(1));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_column_override_exact_nullable() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let record = sqlx::query!(r#\"select id as \"id?: MyInt\" from tweet\"#)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(record.id, Some(MyInt(1)));\n\n    Ok(())\n}\n\n// we don't emit bind parameter typechecks for SQLite so testing the overrides is redundant\n"
  },
  {
    "path": "tests/sqlite/migrate.rs",
    "content": "use sqlx::migrate::Migrator;\nuse sqlx::pool::PoolConnection;\nuse sqlx::sqlite::{Sqlite, SqliteConnection};\nuse sqlx::Executor;\nuse sqlx::Row;\nuse std::path::Path;\n\n#[sqlx::test(migrations = false)]\nasync fn simple(mut conn: PoolConnection<Sqlite>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/sqlite/migrations_simple\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: String = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_simple_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, \"110_suffix\");\n\n    // running it a 2nd time should still work\n    migrator.run(&mut conn).await?;\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = false)]\nasync fn reversible(mut conn: PoolConnection<Sqlite>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/sqlite/migrations_reversible\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 101);\n\n    // roll back nothing (last version)\n    migrator.undo(&mut conn, 20220721125033).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 101);\n\n    // roll back one version\n    migrator.undo(&mut conn, 20220721124650).await?;\n\n    // check outcome\n    let res: i64 = conn\n        .fetch_one(\"SELECT some_payload FROM migrations_reversible_test\")\n        .await?\n        .get(0);\n    assert_eq!(res, 100);\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = false)]\nasync fn no_tx(mut conn: PoolConnection<Sqlite>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n    let migrator = Migrator::new(Path::new(\"tests/sqlite/migrations_no_tx\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = false)]\nasync fn no_tx_reversible(mut conn: PoolConnection<Sqlite>) -> anyhow::Result<()> {\n    clean_up(&mut conn).await?;\n\n    let migrator = Migrator::new(Path::new(\"tests/sqlite/migrations_no_tx_reversible\")).await?;\n\n    // run migration\n    migrator.run(&mut conn).await?;\n\n    // check outcome\n    let res: String = conn.fetch_one(\"PRAGMA JOURNAL_MODE\").await?.get(0);\n    assert_eq!(res, \"wal\".to_string());\n\n    // roll back\n    migrator.undo(&mut conn, -1).await?;\n\n    // check outcome\n    let res: String = conn.fetch_one(\"PRAGMA JOURNAL_MODE\").await?.get(0);\n    assert_eq!(res, \"delete\".to_string());\n\n    Ok(())\n}\n\n/// Ensure that we have a clean initial state.\nasync fn clean_up(conn: &mut SqliteConnection) -> anyhow::Result<()> {\n    conn.execute(\"DROP TABLE migrations_simple_test\").await.ok();\n    conn.execute(\"DROP TABLE migrations_reversible_test\")\n        .await\n        .ok();\n    conn.execute(\"DROP TABLE _sqlx_migrations\").await.ok();\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/migrations/1_user.sql",
    "content": "create table user\n(\n    -- integer primary keys are the most efficient in SQLite\n    user_id  integer primary key,\n    username text unique not null\n);\n"
  },
  {
    "path": "tests/sqlite/migrations/2_post.sql",
    "content": "create table post\n(\n    post_id    integer primary key,\n    user_id    integer not null references user (user_id),\n    content    text    not null,\n    -- Defaults have to be wrapped in parenthesis\n    created_at datetime default (datetime('now'))\n);\n\ncreate index post_created_at on post (created_at desc);\n"
  },
  {
    "path": "tests/sqlite/migrations/3_comment.sql",
    "content": "create table comment\n(\n    comment_id integer primary key,\n    post_id    integer not null references post (post_id),\n    user_id    integer not null references \"user\" (user_id),\n    content    text    not null,\n    created_at datetime default (datetime('now'))\n);\n\ncreate index comment_created_at on comment (created_at desc);\n"
  },
  {
    "path": "tests/sqlite/migrations_no_tx/0_vacuum.sql",
    "content": "-- no-transaction\n\nVACUUM;\n"
  },
  {
    "path": "tests/sqlite/migrations_no_tx_reversible/0_vacuum.down.sql",
    "content": "-- no-transaction\n\nPRAGMA JOURNAL_MODE = DELETE;\n"
  },
  {
    "path": "tests/sqlite/migrations_no_tx_reversible/0_vacuum.up.sql",
    "content": "-- no-transaction\n\nPRAGMA JOURNAL_MODE = WAL;\n"
  },
  {
    "path": "tests/sqlite/migrations_reversible/20220721124650_add_table.down.sql",
    "content": "DROP TABLE migrations_reversible_test;\n"
  },
  {
    "path": "tests/sqlite/migrations_reversible/20220721124650_add_table.up.sql",
    "content": "CREATE TABLE migrations_reversible_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_reversible_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/sqlite/migrations_reversible/20220721125033_modify_column.down.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload - 1;\n"
  },
  {
    "path": "tests/sqlite/migrations_reversible/20220721125033_modify_column.up.sql",
    "content": "UPDATE migrations_reversible_test\nSET some_payload = some_payload + 1;\n"
  },
  {
    "path": "tests/sqlite/migrations_simple/20220721115250_add_test_table.sql",
    "content": "CREATE TABLE migrations_simple_test (\n    some_id BIGINT NOT NULL PRIMARY KEY,\n    some_payload BIGINT NOT NUll\n);\n\nINSERT INTO migrations_simple_test (some_id, some_payload)\nVALUES (1, 100);\n"
  },
  {
    "path": "tests/sqlite/migrations_simple/20220721115524_convert_type.sql",
    "content": "-- Perform a tricky conversion of the payload.\n--\n-- This script will only succeed once and will fail if executed twice.\n\n-- set up temporary target column\nALTER TABLE migrations_simple_test\nADD some_payload_tmp TEXT;\n\n-- perform conversion\n-- This will fail if `some_payload` is already a string column due to the addition.\n-- We add a suffix after the addition to ensure that the SQL database does not silently cast the string back to an \n-- integer.\nUPDATE migrations_simple_test\nSET some_payload_tmp = CAST((some_payload + 10) AS TEXT) || '_suffix';\n\n-- remove original column including the content\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload;\n\n-- prepare new payload column (nullable, so we can copy over the data)\nALTER TABLE migrations_simple_test\nADD some_payload TEXT;\n\n-- copy new values\nUPDATE migrations_simple_test\nSET some_payload = some_payload_tmp;\n\n-- clean up\nALTER TABLE migrations_simple_test\nDROP COLUMN some_payload_tmp;\n"
  },
  {
    "path": "tests/sqlite/rustsec.rs",
    "content": "use sqlx::{AssertSqlSafe, Connection, Error, SqliteConnection};\n\n// https://rustsec.org/advisories/RUSTSEC-2024-0363.html\n//\n// Similar theory to the Postgres exploit in `tests/postgres/rustsec.rs` but much simpler\n// since we just want to overflow the query length itself.\n#[sqlx::test]\nasync fn rustsec_2024_0363() -> anyhow::Result<()> {\n    let overflow_len = 4 * 1024 * 1024 * 1024; // 4 GiB\n\n    // `real_query_prefix` plus `fake_message` will be the first query that SQLite \"sees\"\n    //\n    // Rather contrived because this already represents a regular SQL injection,\n    // but this is the easiest way to demonstrate the exploit for SQLite.\n    let real_query_prefix = \"INSERT INTO injection_target(message) VALUES ('\";\n    let fake_message = \"fake_msg') RETURNING id;\";\n    let real_query_suffix = \"') RETURNING id\";\n\n    // Our actual payload is another query\n    let real_payload =\n        \"\\nUPDATE injection_target SET message = 'you''ve been pwned!' WHERE id = 1;\\n--\";\n\n    // This will parse the query up to `real_payload`.\n    let fake_payload_len = real_query_prefix.len() + fake_message.len();\n\n    // Pretty easy to see that this will overflow to `fake_payload_len`\n    let target_len = overflow_len + fake_payload_len;\n\n    let inject_len = target_len - real_query_prefix.len() - real_query_suffix.len();\n\n    let pad_len = inject_len - fake_message.len() - real_payload.len();\n\n    let mut injected_value = String::with_capacity(inject_len);\n    injected_value.push_str(fake_message);\n    injected_value.push_str(real_payload);\n\n    let padding = \" \".repeat(pad_len);\n    injected_value.push_str(&padding);\n\n    let query = format!(\"{real_query_prefix}{injected_value}{real_query_suffix}\");\n\n    assert_eq!(query.len(), target_len);\n\n    let mut conn = SqliteConnection::connect(\"sqlite://:memory:\").await?;\n\n    sqlx::raw_sql(\n        \"CREATE TABLE injection_target(id INTEGER PRIMARY KEY, message TEXT);\\n\\\n            INSERT INTO injection_target(message) VALUES ('existing message');\",\n    )\n    .execute(&mut conn)\n    .await?;\n\n    let res = sqlx::raw_sql(AssertSqlSafe(query)).execute(&mut conn).await;\n\n    if let Err(e) = res {\n        // Connection rejected the query; we're happy.\n        if matches!(e, Error::Protocol(_)) {\n            return Ok(());\n        }\n\n        panic!(\"unexpected error: {e:?}\");\n    }\n\n    let messages: Vec<String> =\n        sqlx::query_scalar(\"SELECT message FROM injection_target ORDER BY id\")\n            .fetch_all(&mut conn)\n            .await?;\n\n    // If the injection succeeds, `messages` will look like:\n    // [\"you've been pwned!'.to_string(), \"fake_msg\".to_string()]\n    assert_eq!(\n        messages,\n        [\"existing message\".to_string(), \"fake_msg\".to_string()]\n    );\n\n    // Injection didn't affect our database; we're happy.\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/setup.sql",
    "content": "-- https://github.com/prisma/database-schema-examples/tree/master/postgres/basic-twitter#basic-twitter\nCREATE TABLE tweet (\n    id BIGINT NOT NULL PRIMARY KEY,\n    text TEXT NOT NULL,\n    is_sent BOOLEAN NOT NULL DEFAULT TRUE,\n    owner_id BIGINT\n);\nINSERT INTO tweet(id, text, owner_id)\nVALUES (1, '#sqlx is pretty cool!', 1);\n--\nCREATE TABLE tweet_reply (\n    id BIGINT NOT NULL PRIMARY KEY,\n    tweet_id BIGINT NOT NULL,\n    text TEXT NOT NULL,\n    owner_id BIGINT,\n    CONSTRAINT tweet_id_fk FOREIGN KEY (tweet_id) REFERENCES tweet(id)\n);\nINSERT INTO tweet_reply(id, tweet_id, text, owner_id)\nVALUES (1, 1, 'Yeah! #sqlx is indeed pretty cool!', 1);\n--\nCREATE TABLE accounts (\n    id INTEGER NOT NULL PRIMARY KEY,\n    name TEXT NOT NULL,\n    is_active BOOLEAN\n);\nINSERT INTO accounts(id, name, is_active)\nVALUES (1, 'Herp Derpinson', 1);\nCREATE VIEW accounts_view as\nSELECT *\nFROM accounts;\n--\nCREATE TABLE products (\n    product_no INTEGER,\n    name TEXT,\n    price NUMERIC,\n    CONSTRAINT price_greater_than_zero CHECK (price > 0)\n);\n"
  },
  {
    "path": "tests/sqlite/sqlcipher.rs",
    "content": "#![cfg(sqlite_test_sqlcipher)]\n\nuse std::str::FromStr;\n\nuse sqlx::sqlite::SqliteQueryResult;\nuse sqlx::{query, Connection, SqliteConnection};\nuse sqlx::{sqlite::SqliteConnectOptions, ConnectOptions};\nuse tempfile::TempDir;\n\nasync fn new_db_url() -> anyhow::Result<(String, TempDir)> {\n    let dir = TempDir::new()?;\n    let filepath = dir.path().join(\"database.sqlite3\");\n\n    Ok((format!(\"sqlite://{}\", filepath.display()), dir))\n}\n\nasync fn fill_db(conn: &mut SqliteConnection) -> anyhow::Result<SqliteQueryResult> {\n    conn.transaction(|tx| {\n        Box::pin(async move {\n            query(\n                \"\n                CREATE TABLE Company(\n                    Id INT PRIMARY KEY     NOT NULL,\n                    Name           TEXT    NOT NULL,\n                    Salary         REAL\n                 );\n                 \",\n            )\n            .execute(&mut **tx)\n            .await?;\n\n            query(\n                r#\"\n                INSERT INTO Company(Id, Name, Salary)\n                VALUES\n                    (1, \"aaa\", 111),\n                    (2, \"bbb\", 222)\n                \"#,\n            )\n            .execute(&mut **tx)\n            .await\n        })\n    })\n    .await\n    .map_err(|e| e.into())\n}\n\n#[sqlx_macros::test]\nasync fn it_encrypts() -> anyhow::Result<()> {\n    let (url, _dir) = new_db_url().await?;\n\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"key\", \"the_password\")\n        .create_if_missing(true)\n        .connect()\n        .await?;\n\n    fill_db(&mut conn).await?;\n\n    // Create another connection without key, query should fail\n    let mut conn = SqliteConnectOptions::from_str(&url)?.connect().await?;\n\n    assert!(conn\n        .transaction(|tx| {\n            Box::pin(async move { query(\"SELECT * FROM Company;\").fetch_all(&mut **tx).await })\n        })\n        .await\n        .is_err());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_store_and_read_encrypted_data() -> anyhow::Result<()> {\n    let (url, _dir) = new_db_url().await?;\n\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"key\", \"the_password\")\n        .create_if_missing(true)\n        .connect()\n        .await?;\n\n    fill_db(&mut conn).await?;\n\n    // Create another connection with valid key\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"key\", \"the_password\")\n        .connect()\n        .await?;\n\n    let result = conn\n        .transaction(|tx| {\n            Box::pin(async move { query(\"SELECT * FROM Company;\").fetch_all(&mut **tx).await })\n        })\n        .await?;\n\n    assert!(result.len() > 0);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_if_password_is_incorrect() -> anyhow::Result<()> {\n    let (url, _dir) = new_db_url().await?;\n\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"key\", \"the_password\")\n        .create_if_missing(true)\n        .connect()\n        .await?;\n\n    fill_db(&mut conn).await?;\n\n    // Connection with invalid key should not allow to execute queries\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"key\", \"BADBADBAD\")\n        .connect()\n        .await?;\n\n    assert!(conn\n        .transaction(|tx| {\n            Box::pin(async move { query(\"SELECT * FROM Company;\").fetch_all(&mut **tx).await })\n        })\n        .await\n        .is_err());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_honors_order_of_encryption_pragmas() -> anyhow::Result<()> {\n    let (url, _dir) = new_db_url().await?;\n\n    // Make call of cipher configuration mixed with other pragmas,\n    // it should have no effect, encryption related pragmas should be\n    // executed first and allow to establish valid connection\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"cipher_kdf_algorithm\", \"PBKDF2_HMAC_SHA1\")\n        .journal_mode(sqlx::sqlite::SqliteJournalMode::Wal)\n        .pragma(\"cipher_page_size\", \"1024\")\n        .pragma(\"key\", \"the_password\")\n        .foreign_keys(true)\n        .pragma(\"kdf_iter\", \"64000\")\n        .auto_vacuum(sqlx::sqlite::SqliteAutoVacuum::Incremental)\n        .pragma(\"cipher_hmac_algorithm\", \"HMAC_SHA1\")\n        .create_if_missing(true)\n        .connect()\n        .await?;\n\n    fill_db(&mut conn).await?;\n\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"dummy\", \"pragma\")\n        // The cipher configuration set on first connection is\n        // version 3 of SQLCipher, so for second it's enough to set\n        // the compatibility mode.\n        .pragma(\"cipher_compatibility\", \"3\")\n        .pragma(\"key\", \"the_password\")\n        .connect()\n        .await?;\n\n    let result = conn\n        .transaction(|tx| {\n            Box::pin(async move { query(\"SELECT * FROM COMPANY;\").fetch_all(&mut **tx).await })\n        })\n        .await?;\n\n    assert!(result.len() > 0);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_allows_to_rekey_the_db() -> anyhow::Result<()> {\n    let (url, _dir) = new_db_url().await?;\n\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"key\", \"the_password\")\n        .create_if_missing(true)\n        .connect()\n        .await?;\n\n    fill_db(&mut conn).await?;\n\n    // The 'pragma rekey' can be called at any time\n    query(\"PRAGMA rekey = new_password;\")\n        .execute(&mut conn)\n        .await?;\n\n    let mut conn = SqliteConnectOptions::from_str(&url)?\n        .pragma(\"dummy\", \"pragma\")\n        .pragma(\"key\", \"new_password\")\n        .connect()\n        .await?;\n\n    let result = conn\n        .transaction(|tx| {\n            Box::pin(async move { query(\"SELECT * FROM COMPANY;\").fetch_all(&mut **tx).await })\n        })\n        .await?;\n\n    assert!(result.len() > 0);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/sqlite.rs",
    "content": "use futures_util::TryStreamExt;\nuse rand::{Rng, SeedableRng};\nuse rand_xoshiro::Xoshiro256PlusPlus;\nuse sqlx::sqlite::{SqliteConnectOptions, SqliteOperation, SqlitePoolOptions};\nuse sqlx::SqlSafeStr;\nuse sqlx::{\n    query, sqlite::Sqlite, sqlite::SqliteRow, Column, ConnectOptions, Connection, Executor, Row,\n    SqliteConnection, SqlitePool, Statement, TypeInfo,\n};\nuse sqlx_sqlite::LockedSqliteHandle;\nuse sqlx_test::new;\nuse std::future::Future;\nuse std::sync::atomic::{AtomicBool, Ordering};\nuse std::sync::Arc;\n\n#[sqlx_macros::test]\nasync fn it_connects() -> anyhow::Result<()> {\n    Ok(new::<Sqlite>().await?.ping().await?)\n}\n\n#[sqlx_macros::test]\nasync fn it_fetches_and_inflates_row() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    // process rows, one-at-a-time\n    // this reuses the memory of the row\n\n    {\n        let expected = [15, 39, 51];\n        let mut i = 0;\n        let mut s = conn.fetch(\"SELECT 15 UNION SELECT 51 UNION SELECT 39\");\n\n        while let Some(row) = s.try_next().await? {\n            let v1 = row.get::<i32, _>(0);\n            assert_eq!(expected[i], v1);\n            i += 1;\n        }\n    }\n\n    // same query, but fetch all rows at once\n    // this triggers the internal inflation\n\n    let rows = conn\n        .fetch_all(\"SELECT 15 UNION SELECT 51 UNION SELECT 39\")\n        .await?;\n\n    assert_eq!(rows.len(), 3);\n    assert_eq!(rows[0].get::<i32, _>(0), 15);\n    assert_eq!(rows[1].get::<i32, _>(0), 39);\n    assert_eq!(rows[2].get::<i32, _>(0), 51);\n\n    // same query but fetch the first row a few times from a non-persistent query\n    // these rows should be immediately inflated\n\n    let row1 = conn\n        .fetch_one(\"SELECT 15 UNION SELECT 51 UNION SELECT 39\")\n        .await?;\n\n    assert_eq!(row1.get::<i32, _>(0), 15);\n\n    let row2 = conn\n        .fetch_one(\"SELECT 15 UNION SELECT 51 UNION SELECT 39\")\n        .await?;\n\n    assert_eq!(row1.get::<i32, _>(0), 15);\n    assert_eq!(row2.get::<i32, _>(0), 15);\n\n    // same query (again) but make it persistent\n    // and fetch the first row a few times\n\n    let row1 = conn\n        .fetch_one(query(\"SELECT 15 UNION SELECT 51 UNION SELECT 39\"))\n        .await?;\n\n    assert_eq!(row1.get::<i32, _>(0), 15);\n\n    let row2 = conn\n        .fetch_one(query(\"SELECT 15 UNION SELECT 51 UNION SELECT 39\"))\n        .await?;\n\n    assert_eq!(row1.get::<i32, _>(0), 15);\n    assert_eq!(row2.get::<i32, _>(0), 15);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_maths() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let value = sqlx::query(\"select 1 + ?1\")\n        .bind(5_i32)\n        .try_map(|row: SqliteRow| row.try_get::<i32, _>(0))\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(6i32, value);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_bind_multiple_statements_multiple_values() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let values: Vec<i32> = sqlx::query_scalar::<_, i32>(\"select ?; select ?\")\n        .bind(5_i32)\n        .bind(15_i32)\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(values.len(), 2);\n    assert_eq!(values[0], 5);\n    assert_eq!(values[1], 15);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_bind_multiple_statements_same_value() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let values: Vec<i32> = sqlx::query_scalar::<_, i32>(\"select ?1; select ?1\")\n        .bind(25_i32)\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(values.len(), 2);\n    assert_eq!(values[0], 25);\n    assert_eq!(values[1], 25);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_describe_with_pragma() -> anyhow::Result<()> {\n    use sqlx::{Decode, TypeInfo, ValueRef};\n\n    let mut conn = new::<Sqlite>().await?;\n\n    let defaults = sqlx::query(\"pragma table_info (tweet)\")\n        .try_map(|row: SqliteRow| {\n            let val = row.try_get_raw(\"dflt_value\")?;\n            let ty = val.type_info().clone().into_owned();\n\n            let val: Option<i32> = Decode::<Sqlite>::decode(val).map_err(sqlx::Error::Decode)?;\n\n            if val.is_some() {\n                assert_eq!(ty.name(), \"TEXT\");\n            }\n\n            Ok(val)\n        })\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(defaults[0], None);\n    assert_eq!(defaults[2], Some(0));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_binds_positional_parameters_issue_467() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let row: (i32, i32, i32, i32) = sqlx::query_as(\"select ?1, ?1, ?3, ?2\")\n        .bind(5_i32)\n        .bind(500_i32)\n        .bind(1020_i32)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(row.0, 5);\n    assert_eq!(row.1, 5);\n    assert_eq!(row.2, 1020);\n    assert_eq!(row.3, 500);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fetches_in_loop() -> anyhow::Result<()> {\n    // this is trying to check for any data races\n    // there were a few that triggered *sometimes* while building out StatementWorker\n    for _ in 0..1000_usize {\n        let mut conn = new::<Sqlite>().await?;\n        let v: Vec<(i32,)> = sqlx::query_as(\"SELECT 1\").fetch_all(&mut conn).await?;\n\n        assert_eq!(v[0].0, 1);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes_with_pool() -> anyhow::Result<()> {\n    let pool: SqlitePool = SqlitePoolOptions::new()\n        .min_connections(2)\n        .max_connections(2)\n        .test_before_acquire(false)\n        .connect(&dotenvy::var(\"DATABASE_URL\")?)\n        .await?;\n\n    let rows = pool.fetch_all(\"SELECT 1; SElECT 2\").await?;\n\n    assert_eq!(rows.len(), 2);\n\n    Ok(())\n}\n\n#[cfg(sqlite_ipaddr)]\n#[sqlx_macros::test]\nasync fn it_opens_with_extension() -> anyhow::Result<()> {\n    use std::str::FromStr;\n\n    let mut opts = SqliteConnectOptions::from_str(&dotenvy::var(\"DATABASE_URL\")?)?;\n\n    // SAFETY: the `sqlite_ipaddr` cfg is only enabled when we want to test this.\n    unsafe {\n        opts = opts.extension(\"ipaddr\");\n    }\n\n    let mut conn = SqliteConnection::connect_with(&opts).await?;\n    conn.execute(\"SELECT ipmasklen('192.168.16.12/24');\")\n        .await?;\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_opens_in_memory() -> anyhow::Result<()> {\n    // If the filename is \":memory:\", then a private, temporary in-memory database\n    // is created for the connection.\n    let conn = SqliteConnection::connect(\":memory:\").await?;\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_opens_temp_on_disk() -> anyhow::Result<()> {\n    // If the filename is an empty string, then a private, temporary on-disk database will\n    // be created.\n    let conn = SqliteConnection::connect(\"\").await?;\n    conn.close().await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_fails_to_parse() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let res = sqlx::raw_sql(\"SEELCT 1\").execute(&mut conn).await;\n\n    assert!(res.is_err());\n\n    let err = res.unwrap_err().to_string();\n\n    assert_eq!(\n        \"error returned from database: (code: 1) near \\\"SEELCT\\\": syntax error\",\n        err\n    );\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_handles_empty_queries() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let done = conn.execute(\"\").await?;\n\n    assert_eq!(done.rows_affected(), 0);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_binds_parameters() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let v: i32 = sqlx::query_scalar(\"SELECT ?\")\n        .bind(10_i32)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(v, 10);\n\n    let v: (i32, i32) = sqlx::query_as(\"SELECT ?1, ?\")\n        .bind(10_i32)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(v.0, 10);\n    assert_eq!(v.1, 10);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_binds_dollar_parameters() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let v: (i32, i32) = sqlx::query_as(\"SELECT $1, $2\")\n        .bind(10_i32)\n        .bind(11_i32)\n        .fetch_one(&mut conn)\n        .await?;\n\n    assert_eq!(v.0, 10);\n    assert_eq!(v.1, 11);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_executes_queries() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY)\n            \"#,\n        )\n        .await?;\n\n    for index in 1..=10_i32 {\n        let done = sqlx::query(\"INSERT INTO users (id) VALUES (?)\")\n            .bind(index * 2)\n            .execute(&mut conn)\n            .await?;\n\n        assert_eq!(done.rows_affected(), 1);\n    }\n\n    let sum: i32 = sqlx::query_as(\"SELECT id FROM users\")\n        .fetch(&mut conn)\n        .try_fold(0_i32, |acc, (x,): (i32,)| async move { Ok(acc + x) })\n        .await?;\n\n    assert_eq!(sum, 110);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_execute_multiple_statements() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let done = conn\n        .execute(\n            r#\"\nCREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY, other INTEGER);\nINSERT INTO users DEFAULT VALUES;\n            \"#,\n        )\n        .await?;\n\n    assert_eq!(done.rows_affected(), 1);\n\n    for index in 2..5_i32 {\n        let (id, other): (i32, i32) = sqlx::query_as(\n            r#\"\nINSERT INTO users (other) VALUES (?);\nSELECT id, other FROM users WHERE id = last_insert_rowid();\n            \"#,\n        )\n        .bind(index)\n        .fetch_one(&mut conn)\n        .await?;\n\n        assert_eq!(id, index);\n        assert_eq!(other, index);\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_interleaves_reads_and_writes() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let mut cursor = conn.fetch(\n        \"\nCREATE TABLE IF NOT EXISTS _sqlx_test (\n    id INT PRIMARY KEY,\n    text TEXT NOT NULL\n);\n\nSELECT 'Hello World' as _1;\n\nINSERT INTO _sqlx_test (text) VALUES ('this is a test');\n\nSELECT id, text FROM _sqlx_test;\n    \",\n    );\n\n    let row = cursor.try_next().await?.unwrap();\n\n    assert!(\"Hello World\" == row.try_get::<&str, _>(\"_1\")?);\n\n    let row = cursor.try_next().await?.unwrap();\n\n    let id: i64 = row.try_get(\"id\")?;\n    let text: &str = row.try_get(\"text\")?;\n\n    assert_eq!(0, id);\n    assert_eq!(\"this is a test\", text);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_supports_collations() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    // also tests `.lock_handle()`\n    conn.lock_handle()\n        .await?\n        .create_collation(\"test_collation\", |l, r| l.cmp(r).reverse())?;\n\n    let _ = conn\n        .execute(\n            r#\"\nCREATE TEMPORARY TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL COLLATE test_collation)\n            \"#,\n        )\n        .await?;\n\n    sqlx::query(\"INSERT INTO users (name) VALUES (?)\")\n        .bind(\"a\")\n        .execute(&mut conn)\n        .await?;\n    sqlx::query(\"INSERT INTO users (name) VALUES (?)\")\n        .bind(\"b\")\n        .execute(&mut conn)\n        .await?;\n\n    let row: SqliteRow = conn\n        .fetch_one(\"SELECT name FROM users ORDER BY name ASC\")\n        .await?;\n    let name: &str = row.try_get(0)?;\n\n    assert_eq!(name, \"b\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_caches_statements() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    // Initial PRAGMAs are not cached as we are not going to execute\n    // them more than once.\n    assert_eq!(0, conn.cached_statements_size());\n\n    // `&str` queries are not persistent.\n    let row = conn.fetch_one(\"SELECT 100 AS val\").await?;\n    let val: i32 = row.get(\"val\");\n    assert_eq!(val, 100);\n    assert_eq!(0, conn.cached_statements_size());\n\n    // `Query` is persistent by default.\n    let mut conn = new::<Sqlite>().await?;\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT ? AS val\")\n            .bind(i)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: i32 = row.get(\"val\");\n\n        assert_eq!(i, val);\n    }\n    assert_eq!(1, conn.cached_statements_size());\n\n    // Cache can be cleared.\n    conn.clear_cached_statements().await?;\n    assert_eq!(0, conn.cached_statements_size());\n\n    // `Query` is not persistent if `.persistent(false)` is used\n    // explicitly.\n    let mut conn = new::<Sqlite>().await?;\n    for i in 0..2 {\n        let row = sqlx::query(\"SELECT ? AS val\")\n            .bind(i)\n            .persistent(false)\n            .fetch_one(&mut conn)\n            .await?;\n\n        let val: i32 = row.get(\"val\");\n\n        assert_eq!(i, val);\n    }\n    assert_eq!(0, conn.cached_statements_size());\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_prepare_then_execute() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    let mut tx = conn.begin().await?;\n\n    let _ = sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES ( 2, 'Hello, World' )\")\n        .execute(&mut *tx)\n        .await?;\n\n    let tweet_id: i32 = 2;\n\n    let statement = tx\n        .prepare(\"SELECT * FROM tweet WHERE id = ?1\".into_sql_str())\n        .await?;\n\n    assert_eq!(statement.column(0).name(), \"id\");\n    assert_eq!(statement.column(1).name(), \"text\");\n    assert_eq!(statement.column(2).name(), \"is_sent\");\n    assert_eq!(statement.column(3).name(), \"owner_id\");\n\n    assert_eq!(statement.column(0).type_info().name(), \"INTEGER\");\n    assert_eq!(statement.column(1).type_info().name(), \"TEXT\");\n    assert_eq!(statement.column(2).type_info().name(), \"BOOLEAN\");\n    assert_eq!(statement.column(3).type_info().name(), \"INTEGER\");\n\n    let row = statement.query().bind(tweet_id).fetch_one(&mut *tx).await?;\n    let tweet_text: &str = row.try_get(\"text\")?;\n\n    assert_eq!(tweet_text, \"Hello, World\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_resets_prepared_statement_after_fetch_one() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    conn.execute(\"CREATE TEMPORARY TABLE foobar (id INTEGER)\")\n        .await?;\n    conn.execute(\"INSERT INTO foobar VALUES (42)\").await?;\n\n    let r = sqlx::query(\"SELECT id FROM foobar\")\n        .fetch_one(&mut conn)\n        .await?;\n    let x: i32 = r.try_get(\"id\")?;\n    assert_eq!(x, 42);\n\n    conn.execute(\"DROP TABLE foobar\").await?;\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_resets_prepared_statement_after_fetch_many() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    conn.execute(\"CREATE TEMPORARY TABLE foobar (id INTEGER)\")\n        .await?;\n    conn.execute(\"INSERT INTO foobar VALUES (42)\").await?;\n    conn.execute(\"INSERT INTO foobar VALUES (43)\").await?;\n\n    let mut rows = sqlx::query(\"SELECT id FROM foobar\").fetch(&mut conn);\n    let row = rows.try_next().await?.unwrap();\n    let x: i32 = row.try_get(\"id\")?;\n    assert_eq!(x, 42);\n    drop(rows);\n\n    conn.execute(\"DROP TABLE foobar\").await?;\n\n    Ok(())\n}\n\n// https://github.com/launchbadge/sqlx/issues/1300\n#[sqlx_macros::test]\nasync fn concurrent_resets_dont_segfault() {\n    use sqlx::{sqlite::SqliteConnectOptions, ConnectOptions};\n    use std::{str::FromStr, time::Duration};\n\n    let mut conn = SqliteConnectOptions::from_str(\":memory:\")\n        .unwrap()\n        .connect()\n        .await\n        .unwrap();\n\n    sqlx::query(\"CREATE TABLE stuff (name INTEGER, value INTEGER)\")\n        .execute(&mut conn)\n        .await\n        .unwrap();\n\n    sqlx_core::rt::spawn(async move {\n        for i in 0..1000 {\n            sqlx::query(\"INSERT INTO stuff (name, value) VALUES (?, ?)\")\n                .bind(i)\n                .bind(0)\n                .execute(&mut conn)\n                .await\n                .unwrap();\n        }\n    });\n\n    sqlx_core::rt::sleep(Duration::from_millis(1)).await;\n}\n\n// https://github.com/launchbadge/sqlx/issues/1419\n// note: this passes before and after the fix; you need to run it with `--nocapture`\n// to see the panic from the worker thread, which doesn't happen after the fix\n#[sqlx_macros::test]\nasync fn row_dropped_after_connection_doesnt_panic() {\n    let mut conn = SqliteConnection::connect(\":memory:\").await.unwrap();\n\n    let books = sqlx::query(\"SELECT 'hello' AS title\")\n        .fetch_all(&mut conn)\n        .await\n        .unwrap();\n\n    for book in &books {\n        // force the row to be inflated\n        let _title: String = book.get(\"title\");\n    }\n\n    // hold `books` past the lifetime of `conn`\n    drop(conn);\n    sqlx_core::rt::sleep(std::time::Duration::from_secs(1)).await;\n    drop(books);\n}\n\n// note: to repro issue #1467 this should be run in release mode\n// May spuriously fail with UNIQUE constraint failures (which aren't relevant to the original issue)\n// which I have tried to reproduce using the same seed as printed from CI but to no avail.\n// It may be due to some nondeterminism in SQLite itself for all I know.\n#[sqlx_macros::test]\n#[ignore]\nasync fn issue_1467() -> anyhow::Result<()> {\n    let mut conn = SqliteConnectOptions::new()\n        .filename(\":memory:\")\n        .connect()\n        .await?;\n\n    sqlx::query(\n        r#\"\n    CREATE TABLE kv (k PRIMARY KEY, v);\n    CREATE INDEX idx_kv ON kv (v);\n    \"#,\n    )\n    .execute(&mut conn)\n    .await?;\n\n    // Random seed:\n    let seed: [u8; 32] = rand::random();\n    println!(\"RNG seed: {}\", hex::encode(seed));\n\n    // Pre-determined seed:\n    // let mut seed: [u8; 32] = [0u8; 32];\n    // hex::decode_to_slice(\n    //     \"135234871d03fc0479e22f2f06395b6074761bac5fe7dcf205dbe01eef9f7794\",\n    //     &mut seed,\n    // )?;\n\n    // reproducible RNG for testing\n    let mut rng = Xoshiro256PlusPlus::from_seed(seed);\n\n    for i in 0..1_000_000 {\n        if i % 1_000 == 0 {\n            println!(\"{i}\");\n        }\n        let key = rng.gen_range(0..1_000);\n        let value = rng.gen_range(0..1_000);\n        let mut tx = conn.begin().await?;\n\n        let exists = sqlx::query(\"SELECT 1 FROM kv WHERE k = ?\")\n            .bind(key)\n            .fetch_optional(&mut *tx)\n            .await?;\n        if exists.is_some() {\n            sqlx::query(\"UPDATE kv SET v = ? WHERE k = ?\")\n                .bind(value)\n                .bind(key)\n                .execute(&mut *tx)\n                .await?;\n        } else {\n            sqlx::query(\"INSERT INTO kv(k, v) VALUES (?, ?)\")\n                .bind(key)\n                .bind(value)\n                .execute(&mut *tx)\n                .await?;\n        }\n        tx.commit().await?;\n    }\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn concurrent_read_and_write() {\n    let pool: SqlitePool = SqlitePoolOptions::new()\n        .min_connections(2)\n        .connect(\":memory:\")\n        .await\n        .unwrap();\n\n    sqlx::query(\"CREATE TABLE kv (k PRIMARY KEY, v)\")\n        .execute(&pool)\n        .await\n        .unwrap();\n\n    let n = 100;\n\n    let read = sqlx_core::rt::spawn({\n        let mut conn = pool.acquire().await.unwrap();\n\n        async move {\n            for i in 0u32..n {\n                sqlx::query(\"SELECT v FROM kv\")\n                    .bind(i)\n                    .fetch_all(&mut *conn)\n                    .await\n                    .unwrap();\n            }\n        }\n    });\n\n    let write = sqlx_core::rt::spawn({\n        let mut conn = pool.acquire().await.unwrap();\n\n        async move {\n            for i in 0u32..n {\n                sqlx::query(\"INSERT INTO kv (k, v) VALUES (?, ?)\")\n                    .bind(i)\n                    .bind(i * i)\n                    .execute(&mut *conn)\n                    .await\n                    .unwrap();\n            }\n        }\n    });\n\n    read.await;\n    write.await;\n}\n\n#[sqlx_macros::test]\nasync fn test_query_with_progress_handler() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    conn.lock_handle().await?.set_progress_handler(1, move || {\n        assert_eq!(state, \"test\");\n        false\n    });\n\n    match sqlx::query(\"SELECT 'hello' AS title\")\n        .fetch_all(&mut conn)\n        .await\n    {\n        Err(sqlx::Error::Database(err)) => assert_eq!(err.message(), String::from(\"interrupted\")),\n        _ => panic!(\"expected an interrupt\"),\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_multiple_set_progress_handler_calls_drop_old_handler() -> anyhow::Result<()> {\n    let ref_counted_object = Arc::new(0);\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n\n    {\n        let mut conn = new::<Sqlite>().await?;\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_progress_handler(1, move || {\n            println!(\"{o:?}\");\n            false\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_progress_handler(1, move || {\n            println!(\"{o:?}\");\n            false\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_progress_handler(1, move || {\n            println!(\"{o:?}\");\n            false\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        match sqlx::query(\"SELECT 'hello' AS title\")\n            .fetch_all(&mut conn)\n            .await\n        {\n            Err(sqlx::Error::Database(err)) => {\n                assert_eq!(err.message(), String::from(\"interrupted\"))\n            }\n            _ => panic!(\"expected an interrupt\"),\n        }\n\n        conn.lock_handle().await?.remove_progress_handler();\n    }\n\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_with_update_hook() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    static CALLED: AtomicBool = AtomicBool::new(false);\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    conn.lock_handle().await?.set_update_hook(move |result| {\n        assert_eq!(state, \"test\");\n        assert_eq!(result.operation, SqliteOperation::Insert);\n        assert_eq!(result.database, \"main\");\n        assert_eq!(result.table, \"tweet\");\n        assert_eq!(result.rowid, 2);\n        CALLED.store(true, Ordering::Relaxed);\n    });\n\n    let _ = sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES ( 3, 'Hello, World' )\")\n        .execute(&mut conn)\n        .await?;\n    assert!(CALLED.load(Ordering::Relaxed));\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_multiple_set_update_hook_calls_drop_old_handler() -> anyhow::Result<()> {\n    let ref_counted_object = Arc::new(0);\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n\n    {\n        let mut conn = new::<Sqlite>().await?;\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_update_hook(move |_| {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_update_hook(move |_| {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_update_hook(move |_| {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        conn.lock_handle().await?.remove_update_hook();\n    }\n\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_with_commit_hook() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n    static CALLED: AtomicBool = AtomicBool::new(false);\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    conn.lock_handle().await?.set_commit_hook(move || {\n        CALLED.store(true, Ordering::Relaxed);\n        assert_eq!(state, \"test\");\n        false\n    });\n\n    let mut tx = conn.begin().await?;\n    sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES ( 4, 'Hello, World' )\")\n        .execute(&mut *tx)\n        .await?;\n    match tx.commit().await {\n        Err(sqlx::Error::Database(err)) => {\n            assert_eq!(err.message(), String::from(\"constraint failed\"))\n        }\n        _ => panic!(\"expected an error\"),\n    }\n    assert!(CALLED.load(Ordering::Relaxed));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_multiple_set_commit_hook_calls_drop_old_handler() -> anyhow::Result<()> {\n    let ref_counted_object = Arc::new(0);\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n\n    {\n        let mut conn = new::<Sqlite>().await?;\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_commit_hook(move || {\n            println!(\"{o:?}\");\n            true\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_commit_hook(move || {\n            println!(\"{o:?}\");\n            true\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_commit_hook(move || {\n            println!(\"{o:?}\");\n            true\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        conn.lock_handle().await?.remove_commit_hook();\n    }\n\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_query_with_rollback_hook() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    static CALLED: AtomicBool = AtomicBool::new(false);\n    conn.lock_handle().await?.set_rollback_hook(move || {\n        assert_eq!(state, \"test\");\n        CALLED.store(true, Ordering::Relaxed);\n    });\n\n    let mut tx = conn.begin().await?;\n    sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES (5, 'Hello, World' )\")\n        .execute(&mut *tx)\n        .await?;\n    tx.rollback().await?;\n    assert!(CALLED.load(Ordering::Relaxed));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_multiple_set_rollback_hook_calls_drop_old_handler() -> anyhow::Result<()> {\n    let ref_counted_object = Arc::new(0);\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n\n    {\n        let mut conn = new::<Sqlite>().await?;\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_rollback_hook(move || {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_rollback_hook(move || {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_rollback_hook(move || {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        conn.lock_handle().await?.remove_rollback_hook();\n    }\n\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn issue_3150() {\n    // Same bounds as `tokio::spawn()`\n    async fn fake_spawn<F>(future: F) -> F::Output\n    where\n        F: Future + Send + 'static,\n    {\n        future.await\n    }\n\n    fake_spawn(async {\n        let mut db = SqliteConnection::connect(\":memory:\").await.unwrap();\n        sqlx::raw_sql(\"\").execute(&mut db).await.unwrap();\n        db.close().await.unwrap();\n    })\n    .await;\n}\n\n#[cfg(feature = \"sqlite-preupdate-hook\")]\n#[sqlx_macros::test]\nasync fn test_query_with_preupdate_hook_insert() -> anyhow::Result<()> {\n    use sqlx::Decode;\n\n    let mut conn = new::<Sqlite>().await?;\n    static CALLED: AtomicBool = AtomicBool::new(false);\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    conn.lock_handle().await?.set_preupdate_hook({\n        move |result| {\n            assert_eq!(state, \"test\");\n            assert_eq!(result.operation, SqliteOperation::Insert);\n            assert_eq!(result.database, \"main\");\n            assert_eq!(result.table, \"tweet\");\n\n            assert_eq!(4, result.get_column_count());\n            assert_eq!(2, result.get_new_row_id().unwrap());\n            assert_eq!(0, result.get_query_depth());\n            assert_eq!(\n                4,\n                <i64 as Decode<Sqlite>>::decode(result.get_new_column_value(0).unwrap()).unwrap()\n            );\n            assert_eq!(\n                \"Hello, World\",\n                <String as Decode<Sqlite>>::decode(result.get_new_column_value(1).unwrap())\n                    .unwrap()\n            );\n            // out of bounds access should return an error\n            assert!(result.get_new_column_value(4).is_err());\n            // old values aren't available for inserts\n            assert!(result.get_old_column_value(0).is_err());\n            assert!(result.get_old_row_id().is_err());\n\n            CALLED.store(true, Ordering::Relaxed);\n        }\n    });\n\n    let _ = sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES ( 4, 'Hello, World' )\")\n        .execute(&mut conn)\n        .await?;\n\n    assert!(CALLED.load(Ordering::Relaxed));\n    conn.lock_handle().await?.remove_preupdate_hook();\n    let _ = sqlx::query(\"DELETE FROM tweet where id = 4\")\n        .execute(&mut conn)\n        .await?;\n    Ok(())\n}\n\n#[cfg(feature = \"sqlite-preupdate-hook\")]\n#[sqlx_macros::test]\nasync fn test_query_with_preupdate_hook_delete() -> anyhow::Result<()> {\n    use sqlx::Decode;\n\n    let mut conn = new::<Sqlite>().await?;\n    let _ = sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES ( 5, 'Hello, World' )\")\n        .execute(&mut conn)\n        .await?;\n    static CALLED: AtomicBool = AtomicBool::new(false);\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    conn.lock_handle().await?.set_preupdate_hook(move |result| {\n        assert_eq!(state, \"test\");\n        assert_eq!(result.operation, SqliteOperation::Delete);\n        assert_eq!(result.database, \"main\");\n        assert_eq!(result.table, \"tweet\");\n\n        assert_eq!(4, result.get_column_count());\n        assert_eq!(2, result.get_old_row_id().unwrap());\n        assert_eq!(0, result.get_query_depth());\n        assert_eq!(\n            5,\n            <i64 as Decode<Sqlite>>::decode(result.get_old_column_value(0).unwrap()).unwrap()\n        );\n        assert_eq!(\n            \"Hello, World\",\n            <String as Decode<Sqlite>>::decode(result.get_old_column_value(1).unwrap()).unwrap()\n        );\n        // out of bounds access should return an error\n        assert!(result.get_old_column_value(4).is_err());\n        // new values aren't available for deletes\n        assert!(result.get_new_column_value(0).is_err());\n        assert!(result.get_new_row_id().is_err());\n\n        CALLED.store(true, Ordering::Relaxed);\n    });\n\n    let _ = sqlx::query(\"DELETE FROM tweet WHERE id = 5\")\n        .execute(&mut conn)\n        .await?;\n    assert!(CALLED.load(Ordering::Relaxed));\n    Ok(())\n}\n\n#[cfg(feature = \"sqlite-preupdate-hook\")]\n#[sqlx_macros::test]\nasync fn test_query_with_preupdate_hook_update() -> anyhow::Result<()> {\n    use sqlx::Decode;\n    use sqlx::{Value, ValueRef};\n\n    let mut conn = new::<Sqlite>().await?;\n    let _ = sqlx::query(\"INSERT INTO tweet ( id, text ) VALUES ( 6, 'Hello, World' )\")\n        .execute(&mut conn)\n        .await?;\n    static CALLED: AtomicBool = AtomicBool::new(false);\n    let sqlite_value_stored: Arc<std::sync::Mutex<Option<_>>> = Default::default();\n    // Using this string as a canary to ensure the callback doesn't get called with the wrong data pointer.\n    let state = \"test\".to_string();\n    conn.lock_handle().await?.set_preupdate_hook({\n        let sqlite_value_stored = sqlite_value_stored.clone();\n        move |result| {\n            assert_eq!(state, \"test\");\n            assert_eq!(result.operation, SqliteOperation::Update);\n            assert_eq!(result.database, \"main\");\n            assert_eq!(result.table, \"tweet\");\n\n            assert_eq!(4, result.get_column_count());\n            assert_eq!(4, result.get_column_count());\n\n            assert_eq!(2, result.get_old_row_id().unwrap());\n            assert_eq!(2, result.get_new_row_id().unwrap());\n\n            assert_eq!(0, result.get_query_depth());\n            assert_eq!(0, result.get_query_depth());\n\n            assert_eq!(\n                6,\n                <i64 as Decode<Sqlite>>::decode(result.get_old_column_value(0).unwrap()).unwrap()\n            );\n            assert_eq!(\n                6,\n                <i64 as Decode<Sqlite>>::decode(result.get_new_column_value(0).unwrap()).unwrap()\n            );\n\n            assert_eq!(\n                \"Hello, World\",\n                <String as Decode<Sqlite>>::decode(result.get_old_column_value(1).unwrap())\n                    .unwrap()\n            );\n            assert_eq!(\n                \"Hello, World2\",\n                <String as Decode<Sqlite>>::decode(result.get_new_column_value(1).unwrap())\n                    .unwrap()\n            );\n            *sqlite_value_stored.lock().unwrap() =\n                Some(result.get_old_column_value(0).unwrap().to_owned());\n\n            // out of bounds access should return an error\n            assert!(result.get_old_column_value(4).is_err());\n            assert!(result.get_new_column_value(4).is_err());\n\n            CALLED.store(true, Ordering::Relaxed);\n        }\n    });\n\n    let _ = sqlx::query(\"UPDATE tweet SET text = 'Hello, World2' WHERE id = 6\")\n        .execute(&mut conn)\n        .await?;\n\n    assert!(CALLED.load(Ordering::Relaxed));\n    conn.lock_handle().await?.remove_preupdate_hook();\n    let _ = sqlx::query(\"DELETE FROM tweet where id = 6\")\n        .execute(&mut conn)\n        .await?;\n    // Ensure that taking an owned SqliteValue maintains a valid reference after the callback returns\n    assert_eq!(\n        6,\n        <i64 as Decode<Sqlite>>::decode(\n            sqlite_value_stored.lock().unwrap().take().unwrap().as_ref()\n        )\n        .unwrap()\n    );\n    Ok(())\n}\n\n#[cfg(feature = \"sqlite-preupdate-hook\")]\n#[sqlx_macros::test]\nasync fn test_multiple_set_preupdate_hook_calls_drop_old_handler() -> anyhow::Result<()> {\n    let ref_counted_object = Arc::new(0);\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n\n    {\n        let mut conn = new::<Sqlite>().await?;\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_preupdate_hook(move |_| {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_preupdate_hook(move |_| {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        let o = ref_counted_object.clone();\n        conn.lock_handle().await?.set_preupdate_hook(move |_| {\n            println!(\"{o:?}\");\n        });\n        assert_eq!(2, Arc::strong_count(&ref_counted_object));\n\n        conn.lock_handle().await?.remove_preupdate_hook();\n    }\n\n    assert_eq!(1, Arc::strong_count(&ref_counted_object));\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_get_last_error() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let _ = sqlx::query(\"select 1\").fetch_one(&mut conn).await?;\n\n    {\n        let mut handle = conn.lock_handle().await?;\n        assert!(handle.last_error().is_none());\n    }\n\n    let _ = sqlx::query(\"invalid statement\").fetch_one(&mut conn).await;\n\n    {\n        let mut handle = conn.lock_handle().await?;\n        assert!(handle.last_error().is_some());\n    }\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_serialize_deserialize() -> anyhow::Result<()> {\n    let mut conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n\n    sqlx::raw_sql(\"create table foo(bar integer not null, baz text not null)\")\n        .execute(&mut conn)\n        .await?;\n\n    sqlx::query(\"insert into foo(bar, baz) values (1234, 'Lorem ipsum'), (5678, 'dolor sit amet')\")\n        .execute(&mut conn)\n        .await?;\n\n    let serialized = conn.serialize(None).await?;\n\n    // Close and open a new connection to ensure cleanliness.\n    conn.close().await?;\n    let mut conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n\n    conn.deserialize(None, serialized, false).await?;\n\n    let rows = sqlx::query_as::<_, (i32, String)>(\"select bar, baz from foo\")\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(rows.len(), 2);\n\n    assert_eq!(rows[0].0, 1234);\n    assert_eq!(rows[0].1, \"Lorem ipsum\");\n\n    assert_eq!(rows[1].0, 5678);\n    assert_eq!(rows[1].1, \"dolor sit amet\");\n\n    Ok(())\n}\n#[sqlx_macros::test]\nasync fn test_serialize_deserialize_with_schema() -> anyhow::Result<()> {\n    let mut conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n\n    sqlx::raw_sql(\n        \"attach ':memory:' as foo; create table foo.foo(bar integer not null, baz text not null)\",\n    )\n    .execute(&mut conn)\n    .await?;\n\n    sqlx::query(\n        \"insert into foo.foo(bar, baz) values (1234, 'Lorem ipsum'), (5678, 'dolor sit amet')\",\n    )\n    .execute(&mut conn)\n    .await?;\n\n    let serialized = conn.serialize(Some(\"foo\")).await?;\n\n    // Close and open a new connection to ensure cleanliness.\n    conn.close().await?;\n    let mut conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n\n    // Unexpected quirk: the schema must exist before deserialization.\n    sqlx::raw_sql(\"attach ':memory:' as foo\")\n        .execute(&mut conn)\n        .await?;\n\n    conn.deserialize(Some(\"foo\"), serialized, false).await?;\n\n    let rows = sqlx::query_as::<_, (i32, String)>(\"select bar, baz from foo.foo\")\n        .fetch_all(&mut conn)\n        .await?;\n\n    assert_eq!(rows.len(), 2);\n\n    assert_eq!(rows[0].0, 1234);\n    assert_eq!(rows[0].1, \"Lorem ipsum\");\n\n    assert_eq!(rows[1].0, 5678);\n    assert_eq!(rows[1].1, \"dolor sit amet\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_serialize_nonexistent_schema() -> anyhow::Result<()> {\n    let mut conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n\n    let err = conn\n        .serialize(Some(\"foobar\"))\n        .await\n        .expect_err(\"an error should have been returned\");\n\n    let sqlx::Error::Database(dbe) = err else {\n        panic!(\"expected DatabaseError: {err:?}\")\n    };\n\n    assert_eq!(dbe.code().as_deref(), Some(\"1\"));\n    assert_eq!(dbe.message(), \"database foobar does not exist\");\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn test_serialize_invalid_schema() -> anyhow::Result<()> {\n    let mut conn = SqliteConnection::connect(\"sqlite::memory:\").await?;\n\n    let err = conn\n        .serialize(Some(\"foo\\0bar\"))\n        .await\n        .expect_err(\"an error should have been returned\");\n\n    let sqlx::Error::InvalidArgument(msg) = err else {\n        panic!(\"expected InvalidArgument: {err:?}\")\n    };\n\n    assert_eq!(\n        msg,\n        \"schema name \\\"foo\\\\0bar\\\" contains a zero byte at index 3\"\n    );\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_use_transaction_options() -> anyhow::Result<()> {\n    async fn check_txn_state(conn: &mut SqliteConnection, expected: SqliteTransactionState) {\n        let state = transaction_state(&mut conn.lock_handle().await.unwrap());\n        assert_eq!(state, expected);\n    }\n\n    let mut conn = SqliteConnectOptions::new()\n        .in_memory(true)\n        .connect()\n        .await\n        .unwrap();\n\n    check_txn_state(&mut conn, SqliteTransactionState::None).await;\n\n    let mut tx = conn.begin_with(\"BEGIN DEFERRED\").await?;\n    check_txn_state(&mut tx, SqliteTransactionState::None).await;\n    drop(tx);\n\n    let mut tx = conn.begin_with(\"BEGIN IMMEDIATE\").await?;\n    check_txn_state(&mut tx, SqliteTransactionState::Write).await;\n    drop(tx);\n\n    let mut tx = conn.begin_with(\"BEGIN EXCLUSIVE\").await?;\n    check_txn_state(&mut tx, SqliteTransactionState::Write).await;\n    drop(tx);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_can_recover_from_bad_transaction_begin() -> anyhow::Result<()> {\n    let mut conn = SqliteConnectOptions::new()\n        .in_memory(true)\n        .connect()\n        .await\n        .unwrap();\n\n    // This statement doesn't actually start a transaction.\n    assert!(conn.begin_with(\"SELECT 1\").await.is_err());\n\n    // Transaction state bookkeeping should be correctly reset.\n\n    let mut tx = conn.begin_with(\"BEGIN IMMEDIATE\").await?;\n    let value = sqlx::query_scalar::<_, i32>(\"SELECT 1\")\n        .fetch_one(&mut *tx)\n        .await?;\n    assert_eq!(value, 1);\n\n    Ok(())\n}\n\nfn transaction_state(handle: &mut LockedSqliteHandle) -> SqliteTransactionState {\n    use libsqlite3_sys::{sqlite3_txn_state, SQLITE_TXN_NONE, SQLITE_TXN_READ, SQLITE_TXN_WRITE};\n\n    let unchecked_state =\n        unsafe { sqlite3_txn_state(handle.as_raw_handle().as_ptr(), std::ptr::null()) };\n    match unchecked_state {\n        SQLITE_TXN_NONE => SqliteTransactionState::None,\n        SQLITE_TXN_READ => SqliteTransactionState::Read,\n        SQLITE_TXN_WRITE => SqliteTransactionState::Write,\n        _ => panic!(\"unknown txn state: {unchecked_state}\"),\n    }\n}\n\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\nenum SqliteTransactionState {\n    None,\n    Read,\n    Write,\n}\n\n#[sqlx_macros::test]\nasync fn issue_3982() -> anyhow::Result<()> {\n    let mut conn = new::<Sqlite>().await?;\n\n    let r = sqlx::raw_sql(\"insert into products(product_no) values(1)\")\n        .execute(&mut conn)\n        .await?;\n    assert_eq!(r.rows_affected(), 1);\n\n    let (name,) = sqlx::query_as::<_, (Option<String>,)>(\n        r#\"\n        select name from products where name IS NULL\n        \"#,\n    )\n    .fetch_one(&mut conn)\n    .await?;\n\n    assert_eq!(name, None,);\n\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/test-attr.rs",
    "content": "// The no-arg variant is covered by other tests already.\n\nuse sqlx::{Row, SqlitePool};\n\nconst MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate!(\"tests/sqlite/migrations\");\n\n#[sqlx::test]\nasync fn it_gets_a_pool(pool: SqlitePool) -> sqlx::Result<()> {\n    let mut conn = pool.acquire().await?;\n\n    // https://www.sqlite.org/pragma.html#pragma_database_list\n    let db = sqlx::query(\"PRAGMA database_list\")\n        .fetch_one(&mut *conn)\n        .await?;\n\n    let db_name = db.get::<String, _>(2);\n\n    assert!(\n        db_name.ends_with(\"target/sqlx/test-dbs/sqlite_test_attr/it_gets_a_pool.sqlite\"),\n        \"db_name: {:?}\",\n        db_name\n    );\n\n    Ok(())\n}\n\n// This should apply migrations and then `fixtures/users.sql`\n#[sqlx::test(migrations = \"tests/sqlite/migrations\", fixtures(\"users\"))]\nasync fn it_gets_users(pool: SqlitePool) -> sqlx::Result<()> {\n    let usernames: Vec<String> =\n        sqlx::query_scalar(r#\"SELECT username FROM \"user\" ORDER BY username\"#)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(usernames, [\"alice\", \"bob\"]);\n\n    let post_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM post)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!post_exists);\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n#[sqlx::test(migrations = \"tests/sqlite/migrations\", fixtures(\"users\", \"posts\"))]\nasync fn it_gets_posts(pool: SqlitePool) -> sqlx::Result<()> {\n    let post_contents: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM post ORDER BY created_at\")\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_contents,\n        [\n            \"This new computer is lightning-fast!\",\n            \"@alice is a haxxor :(\"\n        ]\n    );\n\n    let comment_exists: bool = sqlx::query_scalar(\"SELECT exists(SELECT 1 FROM comment)\")\n        .fetch_one(&pool)\n        .await?;\n\n    assert!(!comment_exists);\n\n    Ok(())\n}\n\n// Try `migrator`\n#[sqlx::test(migrator = \"MIGRATOR\", fixtures(\"users\", \"posts\", \"comments\"))]\nasync fn it_gets_comments(pool: SqlitePool) -> sqlx::Result<()> {\n    let post_1_comments: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM comment WHERE post_id = ? ORDER BY created_at\")\n            .bind(&1)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(\n        post_1_comments,\n        [\"lol bet ur still bad, 1v1 me\", \"you're on!\"]\n    );\n\n    let post_2_comments: Vec<String> =\n        sqlx::query_scalar(\"SELECT content FROM comment WHERE post_id = ? ORDER BY created_at\")\n            .bind(&2)\n            .fetch_all(&pool)\n            .await?;\n\n    assert_eq!(post_2_comments, [\"lol you're just mad you lost :P\"]);\n\n    Ok(())\n}\n\n#[sqlx::test(\n    migrations = \"tests/sqlite/migrations\",\n    fixtures(path = \"./fixtures\", scripts(\"users\", \"posts\"))\n)]\nasync fn this_should_compile(_pool: SqlitePool) -> sqlx::Result<()> {\n    Ok(())\n}\n"
  },
  {
    "path": "tests/sqlite/types.rs",
    "content": "extern crate time_ as time;\n\nuse sqlx::sqlite::{Sqlite, SqliteRow};\nuse sqlx::Type;\nuse sqlx_core::executor::Executor;\nuse sqlx_core::row::Row;\nuse sqlx_core::types::Text;\nuse sqlx_test::new;\nuse sqlx_test::test_type;\nuse std::borrow::Cow;\nuse std::net::SocketAddr;\nuse std::rc::Rc;\nuse std::sync::Arc;\n\ntest_type!(null<Option<i32>>(Sqlite,\n    \"NULL\" == None::<i32>\n));\n\ntest_type!(bool(Sqlite, \"FALSE\" == false, \"TRUE\" == true));\n\ntest_type!(i32(Sqlite, \"94101\" == 94101_i32));\n\ntest_type!(i64(Sqlite, \"9358295312\" == 9358295312_i64));\n\n// NOTE: This behavior can be surprising. Floating-point parameters are widening to double which can\n//       result in strange rounding.\ntest_type!(f32(Sqlite, \"3.1410000324249268\" == 3.141f32 as f64 as f32));\n\ntest_type!(f64(Sqlite, \"939399419.1225182\" == 939399419.1225182_f64));\n\ntest_type!(str<String>(Sqlite,\n    \"'this is foo'\" == \"this is foo\",\n    \"cast(x'7468697320006973206E756C2D636F6E7461696E696E67' as text)\" == \"this \\0is nul-containing\",\n    \"''\" == \"\"\n));\n\ntest_type!(null_str<Option<String>>(Sqlite,\n    \"NULL\" == None::<String>\n));\n\ntest_type!(bytes<Vec<u8>>(Sqlite,\n    \"X'DEADBEEF'\"\n        == vec![0xDE_u8, 0xAD, 0xBE, 0xEF],\n    \"X''\"\n        == Vec::<u8>::new(),\n    \"X'0000000052'\"\n        == vec![0_u8, 0, 0, 0, 0x52]\n));\n\n#[cfg(feature = \"json\")]\nmod json_tests {\n    use super::*;\n    use serde_json::{json, Value as JsonValue};\n    use sqlx::types::Json;\n    use sqlx_test::test_type;\n\n    test_type!(json<JsonValue>(\n        Sqlite,\n        \"'\\\"Hello, World\\\"'\" == json!(\"Hello, World\"),\n        \"'\\\"😎\\\"'\" == json!(\"😎\"),\n        \"'\\\"🙋‍♀️\\\"'\" == json!(\"🙋‍♀️\"),\n        \"'[\\\"Hello\\\",\\\"World!\\\"]'\" == json!([\"Hello\", \"World!\"])\n    ));\n\n    #[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq)]\n    struct Friend {\n        name: String,\n        age: u32,\n    }\n\n    test_type!(json_struct<Json<Friend>>(\n        Sqlite,\n        \"\\'{\\\"name\\\":\\\"Joe\\\",\\\"age\\\":33}\\'\" == Json(Friend { name: \"Joe\".to_string(), age: 33 })\n    ));\n\n    // NOTE: This is testing recursive (and transparent) usage of the `Json` wrapper. You don't\n    //       need to wrap the Vec in Json<_> to make the example work.\n\n    #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]\n    struct Customer {\n        json_column: Json<Vec<i64>>,\n    }\n\n    test_type!(json_struct_json_column<Json<Customer>>(\n        Sqlite,\n        \"\\'{\\\"json_column\\\":[1,2]}\\'\" == Json(Customer { json_column: Json(vec![1, 2]) })\n    ));\n\n    #[sqlx_macros::test]\n    async fn it_json_extracts() -> anyhow::Result<()> {\n        let mut conn = new::<Sqlite>().await?;\n\n        let value = sqlx::query(\"select JSON_EXTRACT(JSON('{ \\\"number\\\": 42 }'), '$.number') = ?1\")\n            .bind(42_i32)\n            .try_map(|row: SqliteRow| row.try_get::<bool, _>(0))\n            .fetch_one(&mut conn)\n            .await?;\n\n        assert!(value);\n\n        Ok(())\n    }\n}\n\n#[cfg(feature = \"chrono\")]\nmod chrono {\n    use super::*;\n    use sqlx::types::chrono::{DateTime, FixedOffset, NaiveDate, NaiveDateTime, TimeZone, Utc};\n\n    test_type!(chrono_naive_date_time<NaiveDateTime>(Sqlite, \"SELECT datetime({0}) is datetime(?), {0}, ?\",\n        \"'2019-01-02 05:10:20'\" == NaiveDate::from_ymd_opt(2019, 1, 2).unwrap().and_hms_opt(5, 10, 20).unwrap()\n    ));\n\n    test_type!(chrono_date_time_utc<DateTime::<Utc>>(Sqlite, \"SELECT datetime({0}) is datetime(?), {0}, ?\",\n        \"'1996-12-20T00:39:57+00:00'\" == Utc.with_ymd_and_hms(1996, 12, 20, 0, 39, 57).unwrap()\n    ));\n\n    test_type!(chrono_date_time_fixed_offset<DateTime::<FixedOffset>>(Sqlite, \"SELECT datetime({0}) is datetime(?), {0}, ?\",\n        \"'2016-11-08T03:50:23-05:00'\" == DateTime::<Utc>::from(FixedOffset::west_opt(5 * 3600).unwrap().with_ymd_and_hms(2016, 11, 08, 3, 50, 23).unwrap())\n    ));\n}\n\n#[cfg(feature = \"time\")]\nmod time_tests {\n    use super::*;\n    use sqlx::types::time::{Date, OffsetDateTime, PrimitiveDateTime, Time};\n    use time::macros::{date, datetime, time};\n\n    test_type!(time_offset_date_time<OffsetDateTime>(\n        Sqlite,\n        \"SELECT datetime({0}) is datetime(?), {0}, ?\",\n        \"'2015-11-19 01:01:39+01:00'\" == datetime!(2015 - 11 - 19 1:01:39 +1),\n        \"'2014-10-18 00:00:38.697+00:00'\" == datetime!(2014 - 10 - 18 00:00:38.697 +0),\n        \"'2013-09-17 23:59-01:00'\" == datetime!(2013 - 9 - 17 23:59 -1),\n        \"'2016-03-07T22:36:55.135+03:30'\" == datetime!(2016 - 3 - 7 22:36:55.135 +3:30),\n        \"'2017-04-11T14:35+02:00'\" == datetime!(2017 - 4 - 11 14:35 +2),\n    ));\n\n    test_type!(time_primitive_date_time<PrimitiveDateTime>(\n        Sqlite,\n        \"SELECT datetime({0}) is datetime(?), {0}, ?\",\n        \"'2019-01-02 05:10:20'\" == datetime!(2019 - 1 - 2 5:10:20),\n        \"'2018-12-01 04:09:19.543'\" == datetime!(2018 - 12 - 1 4:09:19.543),\n        \"'2017-11-30 03:08'\" == datetime!(2017 - 11 - 30 3:08),\n        \"'2016-10-29T02:07:17'\" == datetime!(2016 - 10 - 29 2:07:17),\n        \"'2015-09-28T01:06:16.432'\" == datetime!(2015 - 9 - 28 1:06:16.432),\n        \"'2014-08-27T00:05'\" == datetime!(2014 - 8 - 27 0:05),\n        \"'2013-07-26 23:04:14Z'\" == datetime!(2013 - 7 - 26 23:04:14),\n        \"'2012-06-25 22:03:13.321Z'\" == datetime!(2012 - 6 - 25 22:03:13.321),\n        \"'2011-05-24 21:02Z'\" == datetime!(2011 - 5 - 24 21:02),\n        \"'2010-04-23T20:01:11Z'\" == datetime!(2010 - 4 - 23 20:01:11),\n        \"'2009-03-22T19:00:10.21Z'\" == datetime!(2009 - 3 - 22 19:00:10.21),\n        \"'2008-02-21T18:59Z'\" == datetime!(2008 - 2 - 21 18:59:00),\n    ));\n\n    test_type!(time_date<Date>(\n        Sqlite,\n        \"SELECT date({0}) is date(?), {0}, ?\",\n        \"'2002-06-04'\" == date!(2002 - 6 - 4),\n    ));\n\n    test_type!(time_time<Time>(\n        Sqlite,\n        \"SELECT time({0}) is time(?), {0}, ?\",\n        \"'21:46:32'\" == time!(21:46:32),\n        \"'20:45:31.133'\" == time!(20:45:31.133),\n        \"'19:44'\" == time!(19:44),\n    ));\n}\n\n#[cfg(feature = \"bstr\")]\nmod bstr {\n    use super::*;\n    use sqlx::types::bstr::BString;\n\n    test_type!(bstring<BString>(Sqlite,\n        \"cast('abc123' as blob)\" == BString::from(&b\"abc123\"[..]),\n        \"x'0001020304'\" == BString::from(&b\"\\x00\\x01\\x02\\x03\\x04\"[..])\n    ));\n}\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid<sqlx::types::Uuid>(Sqlite,\n    \"x'b731678f636f4135bc6f19440c13bd19'\"\n        == sqlx::types::Uuid::parse_str(\"b731678f-636f-4135-bc6f-19440c13bd19\").unwrap(),\n    \"x'00000000000000000000000000000000'\"\n        == sqlx::types::Uuid::parse_str(\"00000000-0000-0000-0000-000000000000\").unwrap()\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid_hyphenated<sqlx::types::uuid::fmt::Hyphenated>(Sqlite,\n    \"'b731678f-636f-4135-bc6f-19440c13bd19'\"\n        == sqlx::types::Uuid::parse_str(\"b731678f-636f-4135-bc6f-19440c13bd19\").unwrap().hyphenated(),\n    \"'00000000-0000-0000-0000-000000000000'\"\n        == sqlx::types::Uuid::parse_str(\"00000000-0000-0000-0000-000000000000\").unwrap().hyphenated()\n));\n\n#[cfg(feature = \"uuid\")]\ntest_type!(uuid_simple<sqlx::types::uuid::fmt::Simple>(Sqlite,\n    \"'b731678f636f4135bc6f19440c13bd19'\"\n        == sqlx::types::Uuid::parse_str(\"b731678f636f4135bc6f19440c13bd19\").unwrap().simple(),\n    \"'00000000000000000000000000000000'\"\n        == sqlx::types::Uuid::parse_str(\"00000000000000000000000000000000\").unwrap().simple()\n));\n\ntest_type!(test_arc<Arc<i32>>(Sqlite, \"1\" == Arc::new(1i32)));\ntest_type!(test_cow<Cow<'_, i32>>(Sqlite, \"1\" == Cow::<i32>::Owned(1i32)));\ntest_type!(test_box<Box<i32>>(Sqlite, \"1\" == Box::new(1i32)));\ntest_type!(test_rc<Rc<i32>>(Sqlite, \"1\" == Rc::new(1i32)));\n\ntest_type!(test_box_str<Box<str>>(Sqlite, \"'John'\" == Box::<str>::from(\"John\")));\ntest_type!(test_cow_str<Cow<'_, str>>(Sqlite, \"'Phil'\" == Cow::<'static, str>::from(\"Phil\")));\ntest_type!(test_arc_str<Arc<str>>(Sqlite, \"'1234'\" == Arc::<str>::from(\"1234\")));\ntest_type!(test_rc_str<Rc<str>>(Sqlite, \"'5678'\" == Rc::<str>::from(\"5678\")));\n\ntest_type!(test_box_slice<Box<[u8]>>(Sqlite, \"X'01020304'\" == Box::<[u8]>::from([1,2,3,4])));\ntest_type!(test_cow_slice<Cow<'_, [u8]>>(Sqlite, \"X'01020304'\" == Cow::<'static, [u8]>::from(&[1,2,3,4])));\ntest_type!(test_arc_slice<Arc<[u8]>>(Sqlite, \"X'01020304'\" == Arc::<[u8]>::from([1,2,3,4])));\ntest_type!(test_rc_slice<Rc<[u8]>>(Sqlite, \"X'01020304'\" == Rc::<[u8]>::from([1,2,3,4])));\n\n#[sqlx_macros::test]\nasync fn test_text_adapter() -> anyhow::Result<()> {\n    #[derive(sqlx::FromRow, Debug, PartialEq, Eq)]\n    struct Login {\n        user_id: i32,\n        socket_addr: Text<SocketAddr>,\n        #[cfg(feature = \"time\")]\n        login_at: time::OffsetDateTime,\n    }\n\n    let mut conn = new::<Sqlite>().await?;\n\n    conn.execute(\n        r#\"\nCREATE TEMPORARY TABLE user_login (\n    user_id INT PRIMARY KEY,\n    socket_addr TEXT NOT NULL,\n    login_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP\n);\n    \"#,\n    )\n    .await?;\n\n    let user_id = 1234;\n    let socket_addr: SocketAddr = \"198.51.100.47:31790\".parse().unwrap();\n\n    sqlx::query(\"INSERT INTO user_login (user_id, socket_addr) VALUES (?, ?)\")\n        .bind(user_id)\n        .bind(Text(socket_addr))\n        .execute(&mut conn)\n        .await?;\n\n    let last_login: Login =\n        sqlx::query_as(\"SELECT * FROM user_login ORDER BY login_at DESC LIMIT 1\")\n            .fetch_one(&mut conn)\n            .await?;\n\n    assert_eq!(last_login.user_id, user_id);\n    assert_eq!(*last_login.socket_addr, socket_addr);\n\n    Ok(())\n}\n\n#[sqlx_macros::test]\nasync fn it_binds_with_borrowed_data() -> anyhow::Result<()> {\n    #[derive(Debug, Type, Clone)]\n    #[sqlx(rename_all = \"lowercase\")]\n    enum Status {\n        New,\n        Open,\n        Closed,\n    }\n\n    let owned = Status::New;\n\n    let mut conn = new::<Sqlite>().await?;\n    sqlx::query(\"select ?\")\n        .bind(Cow::Borrowed(&owned))\n        .fetch_one(&mut conn)\n        .await?;\n    Ok(())\n}\n"
  },
  {
    "path": "tests/ui/mysql/gated/chrono.rs",
    "content": "fn main() {\n    let _ = sqlx::query!(\"select CONVERT(now(), DATE) date\");\n\n    let _ = sqlx::query!(\"select CONVERT(now(), TIME) time\");\n\n    let _ = sqlx::query!(\"select CONVERT(now(), DATETIME) datetime\");\n}\n"
  },
  {
    "path": "tests/ui/mysql/gated/chrono.stderr",
    "content": "error: optional sqlx feature `chrono` required for type DATE of column #1 (\"date\")\n --> $DIR/chrono.rs:2:13\n  |\n2 |     let _ = sqlx::query!(\"select CONVERT(now(), DATE) date\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `chrono` required for type TIME of column #1 (\"time\")\n --> $DIR/chrono.rs:4:13\n  |\n4 |     let _ = sqlx::query!(\"select CONVERT(now(), TIME) time\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `chrono` required for type DATETIME of column #1 (\"datetime\")\n --> $DIR/chrono.rs:6:13\n  |\n6 |     let _ = sqlx::query!(\"select CONVERT(now(), DATETIME) datetime\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui/postgres/deprecated_rename.rs",
    "content": "#[derive(sqlx::Type)]\n#[sqlx(rename = \"foo\")]\nenum Foo {\n    One,\n    Two,\n    Three,\n}\n\nfn main() {\n    compile_error!(\"trybuild test needs to fail for stderr checking\");\n}\n"
  },
  {
    "path": "tests/ui/postgres/deprecated_rename.stderr",
    "content": "error: trybuild test needs to fail for stderr checking\n  --> $DIR/deprecated_rename.rs:10:5\n   |\n10 |     compile_error!(\"trybuild test needs to fail for stderr checking\");\n   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nwarning: use of deprecated function `sqlx::_rename`: `#[sqlx(rename = \"...\")]` is now `#[sqlx(type_name = \"...\")`\n --> $DIR/deprecated_rename.rs:2:8\n  |\n2 | #[sqlx(rename = \"foo\")]\n  |        ^^^^^^\n  |\n  = note: `#[warn(deprecated)]` on by default\n"
  },
  {
    "path": "tests/ui/postgres/gated/chrono.rs",
    "content": "fn main() {\n    let _ = sqlx::query!(\"select now()::date\");\n\n    let _ = sqlx::query!(\"select now()::time\");\n\n    let _ = sqlx::query!(\"select now()::timestamp\");\n\n    let _ = sqlx::query!(\"select now()::timestamptz\");\n\n    let _ = sqlx::query!(\"select $1::date\", ());\n\n    let _ = sqlx::query!(\"select $1::time\", ());\n\n    let _ = sqlx::query!(\"select $1::timestamp\", ());\n\n    let _ = sqlx::query!(\"select $1::timestamptz\", ());\n}\n"
  },
  {
    "path": "tests/ui/postgres/gated/chrono.stderr",
    "content": "error: optional sqlx feature `time` required for type DATE of column #1 (\"now\")\n --> $DIR/chrono.rs:2:13\n  |\n2 |     let _ = sqlx::query!(\"select now()::date\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type TIME of column #1 (\"now\")\n --> $DIR/chrono.rs:4:13\n  |\n4 |     let _ = sqlx::query!(\"select now()::time\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type TIMESTAMP of column #1 (\"now\")\n --> $DIR/chrono.rs:6:13\n  |\n6 |     let _ = sqlx::query!(\"select now()::timestamp\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type TIMESTAMPTZ of column #1 (\"now\")\n --> $DIR/chrono.rs:8:13\n  |\n8 |     let _ = sqlx::query!(\"select now()::timestamptz\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type DATE of param #1\n  --> $DIR/chrono.rs:10:13\n   |\n10 |     let _ = sqlx::query!(\"select $1::date\", ());\n   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type TIME of param #1\n  --> $DIR/chrono.rs:12:13\n   |\n12 |     let _ = sqlx::query!(\"select $1::time\", ());\n   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type TIMESTAMP of param #1\n  --> $DIR/chrono.rs:14:13\n   |\n14 |     let _ = sqlx::query!(\"select $1::timestamp\", ());\n   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `time` required for type TIMESTAMPTZ of param #1\n  --> $DIR/chrono.rs:16:13\n   |\n16 |     let _ = sqlx::query!(\"select $1::timestamptz\", ());\n   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   |\n   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui/postgres/gated/ipnetwork.rs",
    "content": "fn main() {\n    let _ = sqlx::query!(\"select '127.0.0.1'::inet\");\n\n    let _ = sqlx::query!(\"select '2001:4f8:3:ba::/64'::cidr\");\n\n    let _ = sqlx::query!(\"select $1::inet\", ());\n\n    let _ = sqlx::query!(\"select $1::cidr\", ());\n}\n"
  },
  {
    "path": "tests/ui/postgres/gated/ipnetwork.stderr",
    "content": "error: optional sqlx feature `ipnetwork` required for type INET of column #1 (\"inet\")\n --> $DIR/ipnetwork.rs:2:13\n  |\n2 |     let _ = sqlx::query!(\"select '127.0.0.1'::inet\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `ipnetwork` required for type CIDR of column #1 (\"cidr\")\n --> $DIR/ipnetwork.rs:4:13\n  |\n4 |     let _ = sqlx::query!(\"select '2001:4f8:3:ba::/64'::cidr\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `ipnetwork` required for type INET of param #1\n --> $DIR/ipnetwork.rs:6:13\n  |\n6 |     let _ = sqlx::query!(\"select $1::inet\", ());\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `ipnetwork` required for type CIDR of param #1\n --> $DIR/ipnetwork.rs:8:13\n  |\n8 |     let _ = sqlx::query!(\"select $1::cidr\", ());\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui/postgres/gated/uuid.rs",
    "content": "fn main() {\n    let _ = sqlx::query!(\"select 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid\");\n    let _ = sqlx::query!(\"select $1::uuid\", ());\n}\n"
  },
  {
    "path": "tests/ui/postgres/gated/uuid.stderr",
    "content": "error: optional sqlx feature `uuid` required for type UUID of column #1 (\"uuid\")\n --> $DIR/uuid.rs:2:13\n  |\n2 |     let _ = sqlx::query!(\"select 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: optional sqlx feature `uuid` required for type UUID of param #1\n --> $DIR/uuid.rs:3:13\n  |\n3 |     let _ = sqlx::query!(\"select $1::uuid\", ());\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui/postgres/issue_30.rs",
    "content": "fn main() {\n    let query = sqlx::query!(\"select 1 as \\\"'1\\\"\");\n}\n"
  },
  {
    "path": "tests/ui/postgres/issue_30.stderr",
    "content": "error: column name \"\\'1\" is invalid: \"\\'1\" is not a valid Rust identifier\n --> $DIR/issue_30.rs:2:17\n  |\n2 |     let query = sqlx::query!(\"select 1 as \\\"'1\\\"\");\n  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui/postgres/unsupported-type.rs",
    "content": "fn main() {\n    // we're probably not going to get around to the geometric types anytime soon\n    let _ = sqlx::query!(\"select null::circle\");\n    let _ = sqlx::query!(\"select $1::circle\", panic!());\n}\n"
  },
  {
    "path": "tests/ui/postgres/unsupported-type.stderr",
    "content": "error: unsupported type CIRCLE of column #1 (\"circle\")\n --> $DIR/unsupported-type.rs:3:13\n  |\n3 |     let _ = sqlx::query!(\"select null::circle\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n\nerror: unsupported type CIRCLE for param #1\n --> $DIR/unsupported-type.rs:4:13\n  |\n4 |     let _ = sqlx::query!(\"select $1::circle\", panic!());\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui/postgres/wrong_param_type.rs",
    "content": "fn main() {\n    let _query = sqlx::query!(\"select $1::text\", 0i32);\n\n    let _query = sqlx::query!(\"select $1::text\", &0i32);\n\n    let _query = sqlx::query!(\"select $1::text\", Some(0i32));\n\n    let arg = 0i32;\n    let _query = sqlx::query!(\"select $1::text\", arg);\n\n    let arg = Some(0i32);\n    let _query = sqlx::query!(\"select $1::text\", arg);\n    let _query = sqlx::query!(\"select $1::text\", arg.as_ref());\n}\n"
  },
  {
    "path": "tests/ui/postgres/wrong_param_type.stderr",
    "content": "error[E0308]: mismatched types\n --> $DIR/wrong_param_type.rs:2:50\n  |\n2 |     let _query = sqlx::query!(\"select $1::text\", 0i32);\n  |                                                  ^^^^ expected `&str`, found `i32`\n\nerror[E0308]: mismatched types\n --> $DIR/wrong_param_type.rs:4:50\n  |\n4 |     let _query = sqlx::query!(\"select $1::text\", &0i32);\n  |                                                  ^ expected `str`, found `i32`\n  |\n  = note: expected reference `&str`\n             found reference `&i32`\n\nerror[E0308]: mismatched types\n --> $DIR/wrong_param_type.rs:6:50\n  |\n6 |     let _query = sqlx::query!(\"select $1::text\", Some(0i32));\n  |                                                  ^^^^ expected `&str`, found `i32`\n  |\n  = note: expected enum `Option<&str>`\n             found enum `Option<i32>`\n\nerror[E0308]: mismatched types\n --> $DIR/wrong_param_type.rs:9:50\n  |\n9 |     let _query = sqlx::query!(\"select $1::text\", arg);\n  |                                                  ^^^ expected `&str`, found `i32`\n\nerror[E0308]: mismatched types\n  --> $DIR/wrong_param_type.rs:12:50\n   |\n12 |     let _query = sqlx::query!(\"select $1::text\", arg);\n   |                                                  ^^^ expected `&str`, found `i32`\n   |\n   = note: expected enum `Option<&str>`\n              found enum `Option<i32>`\n\nerror[E0308]: mismatched types\n  --> $DIR/wrong_param_type.rs:13:50\n   |\n13 |     let _query = sqlx::query!(\"select $1::text\", arg.as_ref());\n   |                                                  ^^^ expected `str`, found `i32`\n   |\n   = note: expected enum `Option<&str>`\n              found enum `Option<&i32>`\n"
  },
  {
    "path": "tests/ui/sqlite/expression-column-type.rs",
    "content": "fn main() {\n    let _ = sqlx::query!(\"select 1 as id\");\n}\n"
  },
  {
    "path": "tests/ui/sqlite/expression-column-type.stderr",
    "content": "error: database couldn't tell us the type of column #1 (\"id\"); this can happen for columns that are the result of an expression\n --> $DIR/expression-column-type.rs:2:13\n  |\n2 |     let _ = sqlx::query!(\"select 1 as id\");\n  |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)\n"
  },
  {
    "path": "tests/ui-tests.rs",
    "content": "use std::path::Path;\n\n#[test]\n#[ignore]\nfn ui_tests() {\n    let t = trybuild::TestCases::new();\n\n    if cfg!(feature = \"postgres\") {\n        t.compile_fail(\"tests/ui/postgres/*.rs\");\n\n        // UI tests for column types that require gated features\n        if cfg!(not(feature = \"chrono\")) && cfg!(not(feature = \"time\")) {\n            t.compile_fail(\"tests/ui/postgres/gated/chrono.rs\");\n        }\n\n        if cfg!(not(feature = \"uuid\")) {\n            t.compile_fail(\"tests/ui/postgres/gated/uuid.rs\");\n        }\n\n        if cfg!(not(feature = \"ipnet\")) && cfg!(not(feature = \"ipnetwork\")) {\n            t.compile_fail(\"tests/ui/postgres/gated/ipnetwork.rs\");\n        }\n    }\n\n    if cfg!(feature = \"mysql\") {\n        t.compile_fail(\"tests/ui/mysql/*.rs\");\n\n        // UI tests for column types that require gated features\n        if cfg!(not(feature = \"chrono\")) && cfg!(not(feature = \"time\")) {\n            t.compile_fail(\"tests/ui/mysql/gated/chrono.rs\");\n        }\n    }\n\n    if cfg!(feature = \"_sqlite\") {\n        if dotenvy::var(\"DATABASE_URL\").map_or(true, |v| {\n            Path::is_relative(v.trim_start_matches(\"sqlite://\").as_ref())\n        }) {\n            // this isn't `Trybuild`'s fault: https://github.com/dtolnay/trybuild/issues/69#issuecomment-620329526\n            panic!(\"DATABASE_URL must contain an absolute path for SQLite UI tests\")\n        }\n\n        t.compile_fail(\"tests/ui/sqlite/*.rs\");\n    }\n\n    t.compile_fail(\"tests/ui/*.rs\");\n}\n"
  },
  {
    "path": "tests/x.py",
    "content": "#!/usr/bin/env python3\n\nimport subprocess\nimport os\nimport sys\nimport time\nimport argparse\nimport platform\nimport urllib.request\nfrom glob import glob\nfrom docker import start_database\n\nparser = argparse.ArgumentParser()\nparser.add_argument(\"-t\", \"--target\")\nparser.add_argument(\"-e\", \"--target-exact\")\nparser.add_argument(\"-l\", \"--list-targets\", action=\"store_true\")\nparser.add_argument(\"--test\")\n\nargv, unknown = parser.parse_known_args()\n\n# base dir of sqlx workspace\ndir_workspace = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))\n\n# dir of tests\ndir_tests = os.path.join(dir_workspace, \"tests\")\n\n\ndef maybe_fetch_sqlite_extension():\n    \"\"\"\n    For supported platforms, if we're testing SQLite and the file isn't\n    already present, grab a simple extension for testing.\n\n    Returns the extension name if it was downloaded successfully or `None` if not.\n    \"\"\"\n    BASE_URL = \"https://github.com/nalgeon/sqlean/releases/download/0.15.2/\"\n    if platform.system() == \"Darwin\":\n        if platform.machine() == \"arm64\":\n            download_url = BASE_URL + \"/ipaddr.arm64.dylib\"\n            filename = \"ipaddr.dylib\"\n        else:\n            download_url = BASE_URL + \"/ipaddr.dylib\"\n            filename = \"ipaddr.dylib\"\n    elif platform.system() == \"Linux\":\n        download_url = BASE_URL + \"/ipaddr.so\"\n        filename = \"ipaddr.so\"\n    else:\n        # Unsupported OS\n        return None\n\n    if not os.path.exists(filename):\n        content = urllib.request.urlopen(download_url).read()\n        with open(filename, \"wb\") as fd:\n            fd.write(content)\n\n    return filename.split(\".\")[0]\n\n\ndef run(command, comment=None, env=None, service=None, tag=None, args=None, database_url_args=None):\n    if argv.list_targets:\n        if tag:\n            print(f\"{tag}\")\n\n        return\n\n    if argv.target and not tag.startswith(argv.target):\n        return\n\n    if argv.target_exact and tag != argv.target_exact:\n        return\n\n    if comment is not None:\n        print(f\"\\x1b[2m # {comment}\\x1b[0m\")\n\n    environ = env or {}\n\n    if service == \"sqlite\":\n        if maybe_fetch_sqlite_extension() is not None:\n            if environ.get(\"RUSTFLAGS\"):\n                environ[\"RUSTFLAGS\"] += \" --cfg sqlite_ipaddr\"\n            else:\n                environ[\"RUSTFLAGS\"] = \"--cfg sqlite_ipaddr\"\n            if platform.system() == \"Linux\":\n                if os.environ.get(\"LD_LIBRARY_PATH\"):\n                    environ[\"LD_LIBRARY_PATH\"]= os.environ.get(\"LD_LIBRARY_PATH\") + \":\"+ os.getcwd()\n                else:\n                    environ[\"LD_LIBRARY_PATH\"]=os.getcwd()\n\n\n    if service is not None:\n        database_url = start_database(service, database=\"sqlite/sqlite.db\" if service == \"sqlite\" else \"sqlx\", cwd=dir_tests)\n\n        if database_url_args:\n            database_url += \"?\" + database_url_args\n\n        environ[\"DATABASE_URL\"] = database_url\n\n        # show the database url\n        print(f\"\\x1b[94m @ {database_url}\\x1b[0m\")\n\n    command_args = []\n\n    if argv.test:\n        command_args.extend([\"--test\", argv.test])\n\n    if unknown:\n        command_args.extend([\"--\", *unknown])\n\n        if args is not None:\n            command_args.extend(args)\n\n    print(f\"\\x1b[93m $ {command} {' '.join(command_args)}\\x1b[0m\")\n\n    cwd = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))\n    res = subprocess.run(\n        [\n            *command.split(\" \"),\n            *command_args\n        ],\n        env=dict(list(os.environ.items()) + list(environ.items())),\n        cwd=cwd,\n    )\n\n    if res.returncode != 0:\n        sys.exit(res.returncode)\n\n\n# before we start, we clean previous profile data\n# keeping these around can cause weird errors\nfor path in glob(os.path.join(os.path.dirname(__file__), \"target/**/*.gc*\"), recursive=True):\n    os.remove(path)\n\n#\n# check\n#\n\nfor runtime in [\"async-std\", \"tokio\"]:\n    for tls in [\"native-tls\", \"rustls\", \"none\"]:\n        run(\n            f\"cargo c --no-default-features --features all-databases,_unstable-all-types,macros,runtime-{runtime},tls-{tls}\",\n            comment=\"check with async-std\",\n            tag=f\"check_{runtime}_{tls}\"\n        )\n\n#\n# unit test\n#\n\nfor runtime in [\"async-std\", \"tokio\"]:\n    for tls in [\"native-tls\", \"rustls\", \"none\"]:\n        run(\n            f\"cargo test --no-default-features --manifest-path sqlx-core/Cargo.toml --features json,offline,migrate,_rt-{runtime},_tls-{tls}\",\n            comment=\"unit test core\",\n            tag=f\"unit_{runtime}_{tls}\"\n        )\n\n#\n# integration tests\n#\n\nfor runtime in [\"async-std\", \"tokio\"]:\n    for tls in [\"native-tls\", \"rustls\", \"none\"]:\n\n        #\n        # sqlite\n        #\n\n        run(\n            f\"cargo test --no-default-features --features any,sqlite,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n            comment=f\"test sqlite\",\n            service=\"sqlite\",\n            tag=f\"sqlite\" if runtime == \"async-std\" else f\"sqlite_{runtime}\",\n        )\n\n        #\n        # postgres\n        #\n\n        for version in [\"17\", \"16\", \"15\", \"14\", \"13\"]:\n            run(\n                f\"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                comment=f\"test postgres {version}\",\n                service=f\"postgres_{version}\",\n                tag=f\"postgres_{version}\" if runtime == \"async-std\" else f\"postgres_{version}_{runtime}\",\n            )\n\n            if tls != \"none\":\n                ## +ssl\n                run(\n                    f\"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                    comment=f\"test postgres {version} ssl\",\n                    database_url_args=\"sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt\",\n                    service=f\"postgres_{version}\",\n                    tag=f\"postgres_{version}_ssl\" if runtime == \"async-std\" else f\"postgres_{version}_ssl_{runtime}\",\n                )\n\n                ## +client-ssl\n                run(\n                    f\"cargo test --no-default-features --features any,postgres,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                    comment=f\"test postgres {version}_client_ssl no-password\",\n                    database_url_args=\"sslmode=verify-ca&sslrootcert=.%2Ftests%2Fcerts%2Fca.crt&sslkey=%2Ftests%2Fcerts%2Fkeys%2Fclient.key&sslcert=.%2Ftests%2Fcerts%2Fclient.crt\",\n                    service=f\"postgres_{version}_client_ssl\",\n                    tag=f\"postgres_{version}_client_ssl_no_password\" if runtime == \"async-std\" else f\"postgres_{version}_client_ssl_no_password_{runtime}\",\n                )\n\n        #\n        # mysql\n        #\n\n        for version in [\"8\", \"5_7\"]:\n            # Since docker mysql 5.7 using yaSSL(It only supports TLSv1.1), avoid running when using rustls.\n            # https://github.com/docker-library/mysql/issues/567\n            if not(version == \"5_7\" and tls == \"rustls\"):\n                run(\n                    f\"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                    comment=f\"test mysql {version}\",\n                    service=f\"mysql_{version}\",\n                    tag=f\"mysql_{version}\" if runtime == \"async-std\" else f\"mysql_{version}_{runtime}\",\n                )\n\n            ## +client-ssl\n            if tls != \"none\" and not(version == \"5_7\" and tls == \"rustls\"):\n                run(\n                    f\"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                    comment=f\"test mysql {version}_client_ssl no-password\",\n                    database_url_args=\"sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=.%2Ftests%2Fcerts%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt\",\n                    service=f\"mysql_{version}_client_ssl\",\n                    tag=f\"mysql_{version}_client_ssl_no_password\" if runtime == \"async-std\" else f\"mysql_{version}_client_ssl_no_password_{runtime}\",\n                )\n\n        #\n        # mariadb\n        #\n\n        for version in [\"verylatest\", \"10_11\", \"10_6\", \"10_5\", \"10_4\"]:\n            run(\n                f\"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                comment=f\"test mariadb {version}\",\n                service=f\"mariadb_{version}\",\n                tag=f\"mariadb_{version}\" if runtime == \"async-std\" else f\"mariadb_{version}_{runtime}\",\n            )\n\n            ## +client-ssl\n            if tls != \"none\":\n                run(\n                    f\"cargo test --no-default-features --features any,mysql,macros,_unstable-all-types,runtime-{runtime},tls-{tls}\",\n                    comment=f\"test mariadb {version}_client_ssl no-password\",\n                    database_url_args=\"sslmode=verify_ca&ssl-ca=.%2Ftests%2Fcerts%2Fca.crt&ssl-key=%2Ftests%2Fcerts%2Fkeys%2Fclient.key&ssl-cert=.%2Ftests%2Fcerts%2Fclient.crt\",\n                    service=f\"mariadb_{version}_client_ssl\",\n                    tag=f\"mariadb_{version}_client_ssl_no_password\" if runtime == \"async-std\" else f\"mariadb_{version}_client_ssl_no_password_{runtime}\",\n                )\n\n# TODO: Use [grcov] if available\n# ~/.cargo/bin/grcov tests/.cache/target/debug -s sqlx-core/ -t html --llvm --branch -o ./target/debug/coverage\n"
  }
]