From 6d120c54f9368ccc4ea04dd6eaa0a5cb67d9e35e Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 9 Jul 2024 09:22:51 -0400 Subject: [PATCH 01/64] first working version of VS: SELECT FROM NUMBER(36,0) --- .gitattributes | 13 + .github/workflows/broken_links_checker.yml | 39 + .github/workflows/ci-build-next-java.yml | 36 + .github/workflows/ci-build.yml | 164 ++ .github/workflows/dependencies_check.yml | 80 + .github/workflows/dependencies_update.yml | 176 ++ .github/workflows/release.yml | 219 +++ .gitignore | 40 + .project-keeper.yml | 15 + LICENSE | 21 + README.md | 47 + dependencies.md | 108 ++ doc/changes/changelog.md | 3 + doc/changes/changes_0.1.0.md | 60 + doc/design.md | 1 + doc/developers_guide/developers_guide.md | 3 + doc/generated/capabilities.md | 307 ++++ doc/user_guide/snowflake_user_guide.md | 0 error_code_config.yml | 5 + pk_generated_parent.pom | 380 +++++ pom.xml | 190 +++ src/assembly/all-dependencies.xml | 22 + .../SnowflakeColumnMetadataReader.java | 89 + .../snowflake/SnowflakeMetadataReader.java | 45 + .../snowflake/SnowflakeSqlDialect.java | 196 +++ .../snowflake/SnowflakeSqlDialectFactory.java | 30 + .../SnowflakeSqlGenerationVisitor.java | 206 +++ .../SnowflakeTableMetadataReader.java | 31 + ....exasol.adapter.dialects.SqlDialectFactory | 1 + .../adapter/dialects/DialectTestData.java | 69 + .../SnowflakeColumnMetadataReaderTest.java | 58 + .../SnowflakeMetadataReaderTest.java | 32 + .../SnowflakeSqlDialectFactoryTest.java | 30 + .../snowflake/SnowflakeSqlDialectIT.java | 609 +++++++ .../snowflake/SnowflakeSqlDialectTest.java | 136 ++ .../SnowflakeSqlGenerationVisitorTest.java | 119 ++ .../SnowflakeTableMetadataReaderTest.java | 50 + .../docgeneration/CapabilitiesReport.java | 95 ++ ...nowflakeAutogeneratedResourceVerifier.java | 11 + .../exasol/closeafterall/CloseAfterAll.java | 14 + .../closeafterall/CloseAfterAllExtension.java | 48 + .../scalarFunctionsParameterCache.yml | 1517 +++++++++++++++++ src/test/resources/logging.properties | 6 + versionsMavenPluginRules.xml | 18 + 44 files changed, 5339 insertions(+) create mode 100644 .gitattributes create mode 100644 .github/workflows/broken_links_checker.yml create mode 100644 .github/workflows/ci-build-next-java.yml create mode 100644 .github/workflows/ci-build.yml create mode 100644 .github/workflows/dependencies_check.yml create mode 100644 .github/workflows/dependencies_update.yml create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .project-keeper.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 dependencies.md create mode 100644 doc/changes/changelog.md create mode 100644 doc/changes/changes_0.1.0.md create mode 100644 doc/design.md create mode 100644 doc/developers_guide/developers_guide.md create mode 100644 doc/generated/capabilities.md create mode 100644 doc/user_guide/snowflake_user_guide.md create mode 100644 error_code_config.yml create mode 100644 pk_generated_parent.pom create mode 100644 pom.xml create mode 100644 src/assembly/all-dependencies.xml create mode 100644 src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java create mode 100644 src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java create mode 100644 src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java create mode 100644 src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java create mode 100644 src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java create mode 100644 src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java create mode 100644 src/main/resources/META-INF/services/com.exasol.adapter.dialects.SqlDialectFactory create mode 100644 src/test/java/com/exasol/adapter/dialects/DialectTestData.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReaderTest.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactoryTest.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/SnowflakeAutogeneratedResourceVerifier.java create mode 100644 src/test/java/com/exasol/closeafterall/CloseAfterAll.java create mode 100644 src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java create mode 100644 src/test/resources/integration/scalarFunctionsParameterCache.yml create mode 100644 src/test/resources/logging.properties create mode 100644 versionsMavenPluginRules.xml diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..94e0086 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +pk_generated_parent.pom linguist-generated=true +dependencies.md linguist-generated=true +doc/changes/changelog.md linguist-generated=true +.github/workflows/broken_links_checker.yml linguist-generated=true +.github/workflows/ci-build.yml linguist-generated=true +.github/workflows/ci-build-next-java.yml linguist-generated=true +.github/workflows/dependencies_check.yml linguist-generated=true +.github/workflows/dependencies_update.yml linguist-generated=true +.github/workflows/release_droid_print_quick_checksum.yml linguist-generated=true +.github/workflows/release_droid_upload_github_release_assets.yml linguist-generated=true +.github/workflows/release_droid_prepare_original_checksum.yml linguist-generated=true +.settings/org.eclipse.jdt.core.prefs linguist-generated=true +.settings/org.eclipse.jdt.ui.prefs linguist-generated=true diff --git a/.github/workflows/broken_links_checker.yml b/.github/workflows/broken_links_checker.yml new file mode 100644 index 0000000..39612b7 --- /dev/null +++ b/.github/workflows/broken_links_checker.yml @@ -0,0 +1,39 @@ +# Generated by Project Keeper +# https://github.com/exasol/project-keeper/blob/main/project-keeper/src/main/resources/templates/.github/workflows/broken_links_checker.yml +name: Broken Links Checker + +on: + schedule: + - cron: "0 5 * * 0" + push: + branches: + - main + pull_request: + +jobs: + linkChecker: + runs-on: ubuntu-latest + permissions: + contents: read + defaults: + run: + shell: "bash" + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v4 + - name: Configure broken links checker + run: | + mkdir -p ./target + echo '{"aliveStatusCodes": [429, 200], "ignorePatterns": [' \ + '{"pattern": "^https?://(www|dev).mysql.com/"},' \ + '{"pattern": "^https?://(www.)?opensource.org"}' \ + '{"pattern": "^https?://(www.)?eclipse.org"}' \ + '{"pattern": "^https?://projects.eclipse.org"}' \ + ']}' > ./target/broken_links_checker.json + - uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + use-quiet-mode: "yes" + use-verbose-mode: "yes" + config-file: ./target/broken_links_checker.json diff --git a/.github/workflows/ci-build-next-java.yml b/.github/workflows/ci-build-next-java.yml new file mode 100644 index 0000000..e8302fe --- /dev/null +++ b/.github/workflows/ci-build-next-java.yml @@ -0,0 +1,36 @@ +# Generated by Project Keeper +# https://github.com/exasol/project-keeper/blob/main/project-keeper/src/main/resources/templates/.github/workflows/ci-build-next-java.yml +name: CI Build next Java +on: + push: + branches: + - main + pull_request: + +jobs: + java-17-compatibility: + runs-on: ubuntu-latest + defaults: + run: + shell: "bash" + permissions: + contents: read + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up JDK 17 + uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: 17 + cache: "maven" + - name: Run tests and build with Maven + run: | + mvn --batch-mode --update-snapshots clean package -DtrimStackTrace=false \ + -Djava.version=17 \ + -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml new file mode 100644 index 0000000..f13a04c --- /dev/null +++ b/.github/workflows/ci-build.yml @@ -0,0 +1,164 @@ +# This file was generated by Project Keeper. +name: CI Build +on: + push: + branches: [ + main + ] + + pull_request: null +jobs: + matrix-build: + runs-on: ubuntu-20.04 + defaults: + run: { + shell: bash + } + permissions: { + contents: read + } + concurrency: { + group: '${{ github.workflow }}-${{ github.ref }}-${{ matrix.exasol_db_version }}', + cancel-in-progress: true + } + strategy: + fail-fast: false + matrix: + exasol_db_version: [ + 7.1.25, + 8.24.0 + ] + + env: { + DEFAULT_EXASOL_DB_VERSION: 7.1.25 + } + steps: + - name: Free Disk Space + id: free-disk-space + if: ${{ false }} + run: | + sudo rm -rf /usr/local/lib/android + sudo rm -rf /usr/share/dotnet + - name: Checkout the repository + id: checkout + uses: actions/checkout@v4 + with: { + fetch-depth: 0 + } + - name: Set up JDKs + id: setup-java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 17 + cache: maven + - name: Cache SonarCloud packages + id: cache-sonar + uses: actions/cache@v4 + with: { + path: ~/.sonar/cache, + key: '${{ runner.os }}-sonar', + restore-keys: '${{ runner.os }}-sonar' + } + - { + name: Enable testcontainer reuse, + id: enable-testcontainer-reuse, + run: echo 'testcontainers.reuse.enable=true' > "$HOME/.testcontainers.properties" + } + - name: Run tests and build with Maven + id: build-pk-verify + run: | + mvn --batch-mode clean verify \ + -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \ + -DtrimStackTrace=false \ + -Dcom.exasol.dockerdb.image=${{ matrix.exasol_db_version }} + env: { + EXASOL_DB_VERSION: '${{ matrix.exasol_db_version }}' + } + - name: Sonar analysis + id: sonar-analysis + if: ${{ env.SONAR_TOKEN != null && matrix.exasol_db_version == env.DEFAULT_EXASOL_DB_VERSION }} + run: | + mvn --batch-mode org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ + -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \ + -DtrimStackTrace=false \ + -Dsonar.token=$SONAR_TOKEN + env: { + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}', + SONAR_TOKEN: '${{ secrets.SONAR_TOKEN }}' + } + - name: Verify Release Artifacts + id: verify-release-artifacts + run: "print_message() {\n local -r message=$1\n echo \"$message\"\n echo \"$message\" >> \"$GITHUB_STEP_SUMMARY\"\n}\n\nprint_message \"### Release Artifacts\"\n\nIFS=$'\\n' artifacts_array=($ARTIFACTS)\nmissing_files=()\nfor file in \"${artifacts_array[@]}\";\ndo \n echo \"Checking if file $file exists...\"\n if ! [[ -f \"$file\" ]]; then\n print_message \"* ⚠️ \\`$file\\` does not exist ⚠️\"\n echo \"Content of directory $(dirname \"$file\"):\"\n ls \"$(dirname \"$file\")\"\n missing_files+=(\"$file\")\n else\n print_message \"* \\`$file\\` ✅\" \n fi\ndone\nprint_message \"\"\nnumber_of_missing_files=${#missing_files[@]}\nif [[ $number_of_missing_files -gt 0 ]]; then\n print_message \"⚠️ $number_of_missing_files release artifact(s) missing ⚠️\"\n exit 1\nfi\n" + env: { + ARTIFACTS: '${{ steps.build-pk-verify.outputs.release-artifacts }}' + } + - name: Upload artifacts + id: upload-artifacts + uses: actions/upload-artifact@v4 + with: { + name: 'artifacts-exasol-${{ matrix.exasol_db_version }}', + path: '${{ steps.build-pk-verify.outputs.release-artifacts }}', + retention-days: 5 + } + build: + needs: matrix-build + runs-on: ubuntu-latest + defaults: + run: { + shell: bash + } + permissions: { + contents: read, + issues: read + } + outputs: { + release-required: '${{ steps.check-release.outputs.release-required }}' + } + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + with: { + fetch-depth: 0 + } + - name: Set up JDKs + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 17 + cache: maven + - name: Check if release is needed + id: check-release + run: | + if mvn --batch-mode com.exasol:project-keeper-maven-plugin:verify-release --projects .; then + echo "### ✅ Release preconditions met, start release" >> "$GITHUB_STEP_SUMMARY" + echo "release-required=true" >> "$GITHUB_OUTPUT" + else + echo "### 🛑 Not all release preconditions met, skipping release" >> "$GITHUB_STEP_SUMMARY" + echo "See log output for details." >> "$GITHUB_STEP_SUMMARY" + echo "release-required=false" >> "$GITHUB_OUTPUT" + fi + env: { + GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}' + } + start_release: + needs: build + if: ${{ github.ref == 'refs/heads/main' && needs.build.outputs.release-required == 'true' }} + concurrency: { + cancel-in-progress: false, + group: release + } + secrets: inherit + permissions: { + contents: write, + actions: read, + issues: read + } + uses: ./.github/workflows/release.yml + with: { + started-from-ci: true + } diff --git a/.github/workflows/dependencies_check.yml b/.github/workflows/dependencies_check.yml new file mode 100644 index 0000000..9c2365c --- /dev/null +++ b/.github/workflows/dependencies_check.yml @@ -0,0 +1,80 @@ +# This file was generated by Project Keeper. +name: Report Security Issues +on: + workflow_dispatch: null + schedule: + - { + cron: 0 2 * * * + } +jobs: + report_security_issues: + runs-on: ubuntu-latest + defaults: + run: { + shell: bash + } + permissions: { + contents: read, + issues: write + } + outputs: { + created-issues: '${{ steps.security-issues.outputs.created-issues }}' + } + concurrency: { + group: '${{ github.workflow }}-report_security_issues', + cancel-in-progress: true + } + steps: + - { + name: Checkout, + id: checkout, + uses: actions/checkout@v4 + } + - name: Set up JDKs + id: setup-jdks + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 17 + cache: maven + - name: Generate ossindex report + id: ossindex-report + run: | + mvn --batch-mode org.sonatype.ossindex.maven:ossindex-maven-plugin:audit \ + org.sonatype.ossindex.maven:ossindex-maven-plugin:audit-aggregate \ + -Dossindex.reportFile=$(pwd)/ossindex-report.json \ + -Dossindex.fail=false + - name: Report Security Issues + id: security-issues + uses: exasol/python-toolbox/.github/actions/security-issues@main + with: { + format: maven, + command: cat ossindex-report.json, + github-token: '${{ secrets.GITHUB_TOKEN }}' + } + - name: Output security issues (Debugging) + id: debug-print-security-issues + run: | + echo "$CREATED_ISSUES" > test.jsonl + cat test.jsonl + env: { + CREATED_ISSUES: '${{ steps.security-issues.outputs.created-issues }}' + } + start_dependency_udpate: + needs: report_security_issues + if: ${{ needs.report_security_issues.outputs.created-issues }} + concurrency: { + group: '${{ github.workflow }}-start_dependency_update', + cancel-in-progress: false + } + secrets: inherit + permissions: { + contents: write, + pull-requests: write + } + uses: ./.github/workflows/dependencies_update.yml + with: { + vulnerability_issues: '${{ needs.report_security_issues.outputs.created-issues }}' + } diff --git a/.github/workflows/dependencies_update.yml b/.github/workflows/dependencies_update.yml new file mode 100644 index 0000000..0fa7180 --- /dev/null +++ b/.github/workflows/dependencies_update.yml @@ -0,0 +1,176 @@ +# This file was generated by Project Keeper. +name: Update dependencies +on: + workflow_call: + inputs: + vulnerability_issues: { + description: GitHub issues for vulnerable dependencies as JSONL, + required: true, + type: string + } + workflow_dispatch: null +jobs: + update_dependencies: + runs-on: ubuntu-latest + defaults: + run: { + shell: bash + } + permissions: { + contents: write, + pull-requests: write + } + concurrency: { + group: '${{ github.workflow }}', + cancel-in-progress: false + } + steps: + - uses: actions/checkout@v4 + id: checkout + with: { + fetch-depth: 0 + } + - name: Set up JDKs + id: setup-jdks + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 17 + cache: maven + - name: Print issues + id: debug-print-issues + run: | + echo "Issues from Action input: $ISSUES" + env: { + ISSUES: '${{ inputs.vulnerability_issues }}' + } + - name: Fail if not running on a branch + id: check-branch + if: ${{ !startsWith(github.ref, 'refs/heads/') }} + uses: actions/github-script@v7 + with: + script: | + core.setFailed('Not running on a branch, github.ref is ${{ github.ref }}. Please start this workflow only on main or a branch') + - name: Update dependencies + id: update-dependencies + run: | + mvn --batch-mode com.exasol:project-keeper-maven-plugin:update-dependencies --projects . \ + -Dproject-keeper:vulnerabilities="$CREATED_ISSUES" + env: { + CREATED_ISSUES: '${{ inputs.vulnerability_issues }}' + } + - name: Generate Pull Request comment + id: pr-comment + run: | + echo 'comment<> "$GITHUB_OUTPUT" + echo 'This Pull Request was created by [`dependencies_update.yml`](https://github.com/exasol/project-keeper/blob/main/project-keeper/src/main/resources/templates/.github/workflows/dependencies_update.yml) workflow.' >> "$GITHUB_OUTPUT" + if [ -n "$CREATED_ISSUES" ]; then + echo 'It updates dependencies to fix the following vulnerabilities:' >> "$GITHUB_OUTPUT" + echo $CREATED_ISSUES | jq --raw-output '. | "* Closes " + .issue_url + " (" + .cve + ")"' >> "$GITHUB_OUTPUT" + else + echo 'It updates dependencies.' >> "$GITHUB_OUTPUT" + fi + echo >> "$GITHUB_OUTPUT" + echo '# ⚠️ Notes ⚠️' >> "$GITHUB_OUTPUT" + echo '## Run PK fix manually' >> "$GITHUB_OUTPUT" + echo 'Due to restrictions workflow `dependencies_update.yml` cannot update other workflows, see https://github.com/exasol/project-keeper/issues/578 for details.' >> "$GITHUB_OUTPUT" + echo 'Please checkout this PR locally and run `mvn com.exasol:project-keeper-maven-plugin:fix --projects .`' >> "$GITHUB_OUTPUT" + echo '## This PR does not trigger CI workflows' >> "$GITHUB_OUTPUT" + echo 'Please click the **Close pull request** button and then **Reopen pull request** to trigger running checks.' >> "$GITHUB_OUTPUT" + echo 'See https://github.com/exasol/project-keeper/issues/534 for details.' >> "$GITHUB_OUTPUT" + echo 'EOF' >> "$GITHUB_OUTPUT" + + cat "$GITHUB_OUTPUT" + env: { + CREATED_ISSUES: '${{ inputs.vulnerability_issues }}' + } + - name: Generate Pull Request Title + id: pr-title + run: | + if [ -n "$CREATED_ISSUES" ]; then + echo "Security issues are available" + echo "title=🔐 Update dependencies to fix vulnerabilities" >> "$GITHUB_OUTPUT" + else + echo "Security issues are not available" + echo "title=Update dependencies" >> "$GITHUB_OUTPUT" + fi + + cat "$GITHUB_OUTPUT" + env: { + CREATED_ISSUES: '${{ inputs.vulnerability_issues }}' + } + - name: Configure git + id: configure-git + run: | + git config --global user.email "opensource@exasol.com" + git config --global user.name "Automatic Dependency Updater" + - name: Create branch + id: create-branch + if: ${{ github.ref == 'refs/heads/main' }} + run: | + branch_name="dependency-update/$(date "+%Y%m%d%H%M%S")" + echo "Creating branch $branch_name" + git checkout -b "$branch_name" + - name: Commit changes & push + id: publish-branch + if: ${{ startsWith(github.ref, 'refs/heads/' ) }} + run: | + branch_name=$(git rev-parse --abbrev-ref HEAD) + echo "Current branch: $branch_name" + echo "git diff --stat" + git diff --stat + echo "git diff --numstat" + git diff --numstat + echo "git diff --name-status" + git diff --name-status + echo "Adding untracked files:" + git add . --verbose --all + echo "Committing changes..." + git commit --message "$TITLE" + echo "Pushing branch $branch_name..." + git push --set-upstream origin "$branch_name" + echo "Done." + env: { + TITLE: '${{ steps.pr-title.outputs.title }}' + } + - name: Create pull request + id: create-pr + if: ${{ github.ref == 'refs/heads/main' }} + run: | + pr_url=$(gh pr create --base main --title "$TITLE" --body "$COMMENT") + echo "Created Pull Request: $pr_url" + echo "pr_url=$pr_url" >> "$GITHUB_OUTPUT" + env: { + COMMENT: '${{ steps.pr-comment.outputs.comment }}', + TITLE: '${{ steps.pr-title.outputs.title }}', + GH_TOKEN: '${{ github.token }}' + } + - name: Report failure Status to Slack channel + id: report-failure-slack + if: ${{ always() }} + uses: ravsamhq/notify-slack-action@v2 + with: { + status: '${{ job.status }}', + token: '${{ secrets.GITHUB_TOKEN }}', + notification_title: 'Dependency check in {repo} has {status_message}', + message_format: '{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>', + notify_when: 'failure,cancelled,warnings' + } + env: { + SLACK_WEBHOOK_URL: '${{ secrets.INTEGRATION_TEAM_SLACK_NOTIFICATION_WEBHOOK }}' + } + - name: Report new Pull Request to Slack channel + id: report-pr-slack + if: ${{ steps.create-pr.outputs.pr_url }} + uses: ravsamhq/notify-slack-action@v2 + with: { + status: '${{ job.status }}', + token: '${{ secrets.GITHUB_TOKEN }}', + notification_title: 'Dependency update for {repo} created a Pull Request', + message_format: '{workflow} created Pull Request ${{ steps.create-pr.outputs.pr_url }}' + } + env: { + SLACK_WEBHOOK_URL: '${{ secrets.INTEGRATION_TEAM_SLACK_NOTIFICATION_WEBHOOK }}' + } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..2a8bbf7 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,219 @@ +# This file was generated by Project Keeper. +name: Release +on: + workflow_call: + inputs: + started-from-ci: { + description: 'Marks this release as started from CI, skipping precondition check', + type: boolean, + required: true, + default: false + } + workflow_dispatch: + inputs: + skip-maven-central: { + description: Skip deployment to Maven Central, + required: true, + type: boolean, + default: false + } + skip-github-release: { + description: Skip creating the GitHub release, + required: true, + type: boolean, + default: false + } +jobs: + release: + runs-on: ubuntu-latest + defaults: + run: { + shell: bash + } + concurrency: { + group: '${{ github.workflow }}', + cancel-in-progress: false + } + permissions: { + contents: write, + actions: read, + issues: read + } + steps: + - name: Checkout the repository + id: checkout + uses: actions/checkout@v4 + with: { + fetch-depth: 0 + } + - name: Set up Maven Central Repository + id: configure-maven-central-credentials + if: ${{ false }} + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 17 + cache: maven + server-id: ossrh + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-private-key: ${{ secrets.OSSRH_GPG_SECRET_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE + - name: Set up JDKs + id: setup-jdks + if: ${{ ! false }} + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: | + 11 + 17 + cache: maven + - name: Fail if not running on main branch + id: check-main-branch + if: ${{ github.ref != 'refs/heads/main' }} + uses: actions/github-script@v7 + with: + script: | + core.setFailed('Not running on main branch, github.ref is ${{ github.ref }}. Please start this workflow only on main') + - name: Check CI build of this commit succeeded + id: check-ci-build-status + if: ${{ ! inputs.started-from-ci }} + run: | + echo "Commit SHA: $COMMIT_SHA" + gh run list --workflow ci-build.yml --branch main --event push --commit $COMMIT_SHA + ci_build_status=$(gh run list --workflow ci-build.yml --branch main --event push --commit $COMMIT_SHA --json conclusion --template '{{range .}}{{.conclusion}}{{"\n"}}{{end}}') + echo "CI build status at commit $COMMIT_SHA was '$ci_build_status'" + if [[ "$ci_build_status" != "success" ]]; then + gh run list --workflow ci-build.yml --commit $COMMIT_SHA >> $GITHUB_STEP_SUMMARY + echo "Status of CI build for commit $COMMIT_SHA was '$ci_build_status', expected 'success'" >> $GITHUB_STEP_SUMMARY + cat $GITHUB_STEP_SUMMARY + exit 1 + fi + env: { + COMMIT_SHA: '${{ github.sha }}', + GH_TOKEN: '${{ github.token }}' + } + - name: Verify release preconditions + id: verify-release + run: | + mvn --batch-mode com.exasol:project-keeper-maven-plugin:verify-release --projects . + echo "$GITHUB_OUTPUT" + env: { + GITHUB_TOKEN: '${{ github.token }}' + } + - { + name: Build project, + id: build, + run: mvn --batch-mode -DskipTests clean verify + } + - { + name: List secret GPG keys, + id: list-secret-gpg-keys, + if: '${{ false && (! inputs.skip-maven-central) }}', + run: gpg --list-secret-keys + } + - name: Publish to Central Repository + id: deploy-maven-central + if: ${{ false && (! inputs.skip-maven-central) }} + run: | + echo "#### Maven Central Release" >> "$GITHUB_STEP_SUMMARY" + mvn --batch-mode -Dgpg.skip=false -DskipTests deploy + echo "Published to Maven Central ✅" >> "$GITHUB_STEP_SUMMARY" + env: { + MAVEN_USERNAME: '${{ secrets.OSSRH_USERNAME }}', + MAVEN_PASSWORD: '${{ secrets.OSSRH_PASSWORD }}', + MAVEN_GPG_PASSPHRASE: '${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }}' + } + - name: Calculate Artifact Checksums + id: artifact-checksum + if: ${{ ! inputs.skip-github-release }} + run: | + echo "Calculating sha256 checksum for artifact files" + echo "artifacts<> "$GITHUB_OUTPUT" + IFS=$'\n' artifacts_array=($ARTIFACTS) + for file in "${artifacts_array[@]}"; + do + full_path=$(realpath "$file") + echo "Calculate sha256sum for file '$full_path'" + file_dir="$(dirname "$full_path")" + file_name=$(basename "$full_path") + pushd "$file_dir" + checksum_file_name="${file_name}.sha256" + sha256sum "$file_name" > "$checksum_file_name" + echo "$full_path" >> "$GITHUB_OUTPUT" + echo "${file_dir}/$checksum_file_name" >> "$GITHUB_OUTPUT" + popd + done + echo "EOF" >> "$GITHUB_OUTPUT" + echo "Full artifact file list" + cat "$GITHUB_OUTPUT" + env: { + ARTIFACTS: '${{ steps.verify-release.outputs.release-artifacts }}' + } + - name: Create GitHub Release + id: create-github-release + if: ${{ ! inputs.skip-github-release }} + run: | + echo "### GitHub Release" >> "$GITHUB_STEP_SUMMARY" + IFS=$'\n' artifacts_array=($ARTIFACTS) + echo "#### Attaching Release Artifacts" >> "$GITHUB_STEP_SUMMARY" + for file in "${artifacts_array[@]}"; + do + echo "Attaching artifact '$file'" + echo "* \`$file\`" >> "$GITHUB_STEP_SUMMARY" + done + echo "" >> "$GITHUB_STEP_SUMMARY" + release_url=$(gh release create --latest --title "$TITLE" --notes "$NOTES" --target main $TAG "${artifacts_array[@]}") + echo "Created release $TAG with title '$TITLE' at $release_url ✅" >> "$GITHUB_STEP_SUMMARY" + echo "release-url=$release_url" >> "$GITHUB_OUTPUT" + + # [impl->dsn~release-workflow.create-golang-tags~1] + echo "#### Creating Additional Tags" >> "$GITHUB_STEP_SUMMARY" + IFS=$'\n' tags_array=($ADDITIONAL_TAGS) + for tag in "${tags_array[@]}"; + do + echo "Creating tag '$tag'" + git tag "$tag" + git push origin "$tag" + echo "* \`$tag\`" >> "$GITHUB_STEP_SUMMARY" + done + + git fetch --tags origin + env: { + GH_TOKEN: '${{ github.token }}', + TAG: '${{ steps.verify-release.outputs.release-tag }}', + ADDITIONAL_TAGS: '${{ steps.verify-release.outputs.additional-release-tags }}', + NOTES: '${{ steps.verify-release.outputs.release-notes }}', + TITLE: '${{ steps.verify-release.outputs.release-title }}', + ARTIFACTS: '${{ steps.artifact-checksum.outputs.artifacts }}' + } + - name: Report failure Status to Slack channel + id: report-failure-status-slack + if: ${{ always() }} + uses: ravsamhq/notify-slack-action@v2 + with: { + status: '${{ job.status }}', + token: '${{ github.token }}', + notification_title: 'Release build in {repo} has {status_message}', + message_format: '{emoji} *{workflow}* {status_message} in <{repo_url}|{repo}>', + notify_when: 'failure,cancelled,warnings,skipped' + } + env: { + SLACK_WEBHOOK_URL: '${{ secrets.INTEGRATION_TEAM_SLACK_NOTIFICATION_WEBHOOK }}' + } + - name: Report new release to Slack channel + id: report-new-release-slack + if: ${{ steps.create-github-release.outputs.release-url }} + uses: ravsamhq/notify-slack-action@v2 + with: { + status: '${{ job.status }}', + token: '${{ github.token }}', + notification_title: 'Release build for {repo} created a new release', + message_format: '{workflow} created release ${{ steps.create-github-release.outputs.release-url }}' + } + env: { + SLACK_WEBHOOK_URL: '${{ secrets.INTEGRATION_TEAM_SLACK_NOTIFICATION_WEBHOOK }}' + } diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b1e8103 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +/target/ +pom.xml.versionsBackup + +# Eclipse and Maven +.classpath +.project +/.settings/org.eclipse.core.resources.prefs +/.settings/org.eclipse.m2e.core.prefs +/.settings/org.eclipse.jdt.apt.core.prefs +# .settings : we need Eclipse settings for code formatter and clean-up rules +target +.cache +dependency-reduced-pom.xml + +# Intellij +.idea +# Intellij recommends to share iml files, however, better don't share files which might be outdated +*.iml + + +# Others +.DS_Store +*.swp +local +Scripts +.dbeaver* +**/*.log +.directory +venv/ + +~* +*.lock +*.bak +*.orig +*.old +*.md.html +/.apt_generated/ +/.apt_generated_tests/ +*.flattened-pom.xml +/bin/ diff --git a/.project-keeper.yml b/.project-keeper.yml new file mode 100644 index 0000000..3af4681 --- /dev/null +++ b/.project-keeper.yml @@ -0,0 +1,15 @@ +sources: + - type: maven + path: pom.xml + modules: + - integration_tests + - udf_coverage + - jar_artifact +version: + fromSource: pom.xml +build: + runnerOs: ubuntu-20.04 + freeDiskSpace: false + exasolDbVersions: + - "7.1.25" + - "8.24.0" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7752ffc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Exasol + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8ffe367 --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# Snowflake Virtual Schema + +[![Build Status](https://github.com/exasol/snowflake-virtual-schema/actions/workflows/ci-build.yml/badge.svg)](https://github.com/exasol/snowflake-virtual-schema/actions/workflows/ci-build.yml) + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=alert_status)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) + +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=security_rating)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=sqale_rating)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) +[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=sqale_index)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) + +[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=code_smells)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=coverage)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) +[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=duplicated_lines_density)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=com.exasol%3Asnowflake-virtual-schema&metric=ncloc)](https://sonarcloud.io/dashboard?id=com.exasol%3Asnowflake-virtual-schema) + +# Overview + +The **Snowflake Virtual Schema** provides an abstraction layer that makes an external [Snowflake](https://www.Snowflake.org/) database accessible from an Exasol database through regular SQL commands. The contents of the external Snowflake database are mapped to virtual tables which look like and can be queried as any regular Exasol table. + +If you want to set up a Virtual Schema for a different database system, please head over to the [Virtual Schemas Repository][virtual-schemas]. + +## Features + +* Access a Snowflake database using a Virtual Schema. + +## Table of Contents + +### Information for Users + +* [Virtual Schema User Guide](https://docs.exasol.com/database_concepts/virtual_schemas.htm) +* [Snowflake Dialect User Guide](doc/user_guide/Snowflake_user_guide.md) +* [List of supported capabilities](doc/generated/capabilities.md) +* [Changelog](doc/changes/changelog.md) +* [Dependencies](dependencies.md) + +Find all the documentation in the [Virtual Schemas project][vs-doc]. + +## Information for Developers + +* [Virtual Schema API Documentation](https://github.com/exasol/virtual-schema-common-java/blob/main/doc/development/api/virtual_schema_api.md) +* [Remote logging](https://docs.exasol.com/db/latest/database_concepts/virtual_schema/logging.htm) + +## Additional Resources + +* [Dependencies](dependencies.md) +* [Changelog](doc/changes/changelog.md) diff --git a/dependencies.md b/dependencies.md new file mode 100644 index 0000000..0ad946f --- /dev/null +++ b/dependencies.md @@ -0,0 +1,108 @@ + +# Dependencies + +## Compile Dependencies + +| Dependency | License | +| ------------------------------- | --------------------------------------------- | +| [Virtual Schema Common JDBC][0] | [MIT License][1] | +| [error-reporting-java][2] | [MIT License][3] | +| [Snowflake JDBC Driver][4] | [The Apache Software License, Version 2.0][5] | + +## Test Dependencies + +| Dependency | License | +| ----------------------------------------------- | --------------------------------------------- | +| [Virtual Schema Common JDBC][0] | [MIT License][1] | +| [Hamcrest][6] | [BSD License 3][7] | +| [JUnit Jupiter (Aggregator)][8] | [Eclipse Public License v2.0][9] | +| [mockito-junit-jupiter][10] | [MIT][11] | +| [Test containers for Exasol on Docker][12] | [MIT License][13] | +| [Testcontainers :: JUnit Jupiter Extension][14] | [MIT][15] | +| [Testcontainers :: Localstack][14] | [MIT][15] | +| [Test Database Builder for Java][16] | [MIT License][17] | +| [Matcher for SQL Result Sets][18] | [MIT License][19] | +| [udf-debugging-java][20] | [MIT License][21] | +| [Markdown Generator][22] | [The Apache Software License, Version 2.0][5] | +| [Autogenerated resource verifier][23] | [MIT License][24] | +| [virtual-schema-shared-integration-tests][25] | [MIT License][26] | +| [JaCoCo :: Agent][27] | [EPL-2.0][28] | + +## Plugin Dependencies + +| Dependency | License | +| ------------------------------------------------------- | --------------------------------- | +| [SonarQube Scanner for Maven][29] | [GNU LGPL 3][30] | +| [Apache Maven Toolchains Plugin][31] | [Apache-2.0][32] | +| [Apache Maven Compiler Plugin][33] | [Apache-2.0][32] | +| [Apache Maven Enforcer Plugin][34] | [Apache-2.0][32] | +| [Maven Flatten Plugin][35] | [Apache Software Licenese][32] | +| [org.sonatype.ossindex.maven:ossindex-maven-plugin][36] | [ASL2][5] | +| [Maven Surefire Plugin][37] | [Apache-2.0][32] | +| [Versions Maven Plugin][38] | [Apache License, Version 2.0][32] | +| [duplicate-finder-maven-plugin Maven Mojo][39] | [Apache License 2.0][40] | +| [Apache Maven Assembly Plugin][41] | [Apache-2.0][32] | +| [Apache Maven JAR Plugin][42] | [Apache-2.0][32] | +| [Artifact reference checker and unifier][43] | [MIT License][44] | +| [Project Keeper Maven plugin][45] | [The MIT License][46] | +| [Apache Maven Dependency Plugin][47] | [Apache-2.0][32] | +| [Exec Maven Plugin][48] | [Apache License 2][32] | +| [Maven Failsafe Plugin][49] | [Apache-2.0][32] | +| [JaCoCo :: Maven Plugin][50] | [EPL-2.0][28] | +| [error-code-crawler-maven-plugin][51] | [MIT License][52] | +| [Reproducible Build Maven Plugin][53] | [Apache 2.0][5] | + +[0]: https://github.com/exasol/virtual-schema-common-jdbc/ +[1]: https://github.com/exasol/virtual-schema-common-jdbc/blob/main/LICENSE +[2]: https://github.com/exasol/error-reporting-java/ +[3]: https://github.com/exasol/error-reporting-java/blob/main/LICENSE +[4]: https://www.snowflake.net/ +[5]: http://www.apache.org/licenses/LICENSE-2.0.txt +[6]: http://hamcrest.org/JavaHamcrest/ +[7]: http://opensource.org/licenses/BSD-3-Clause +[8]: https://junit.org/junit5/ +[9]: https://www.eclipse.org/legal/epl-v20.html +[10]: https://github.com/mockito/mockito +[11]: https://opensource.org/licenses/MIT +[12]: https://github.com/exasol/exasol-testcontainers/ +[13]: https://github.com/exasol/exasol-testcontainers/blob/main/LICENSE +[14]: https://java.testcontainers.org +[15]: http://opensource.org/licenses/MIT +[16]: https://github.com/exasol/test-db-builder-java/ +[17]: https://github.com/exasol/test-db-builder-java/blob/main/LICENSE +[18]: https://github.com/exasol/hamcrest-resultset-matcher/ +[19]: https://github.com/exasol/hamcrest-resultset-matcher/blob/main/LICENSE +[20]: https://github.com/exasol/udf-debugging-java/ +[21]: https://github.com/exasol/udf-debugging-java/blob/main/LICENSE +[22]: https://github.com/Steppschuh/Java-Markdown-Generator +[23]: https://github.com/exasol/autogenerated-resource-verifier-java/ +[24]: https://github.com/exasol/autogenerated-resource-verifier-java/blob/main/LICENSE +[25]: https://github.com/exasol/virtual-schema-shared-integration-tests/ +[26]: https://github.com/exasol/virtual-schema-shared-integration-tests/blob/main/LICENSE +[27]: https://www.eclemma.org/jacoco/index.html +[28]: https://www.eclipse.org/legal/epl-2.0/ +[29]: http://sonarsource.github.io/sonar-scanner-maven/ +[30]: http://www.gnu.org/licenses/lgpl.txt +[31]: https://maven.apache.org/plugins/maven-toolchains-plugin/ +[32]: https://www.apache.org/licenses/LICENSE-2.0.txt +[33]: https://maven.apache.org/plugins/maven-compiler-plugin/ +[34]: https://maven.apache.org/enforcer/maven-enforcer-plugin/ +[35]: https://www.mojohaus.org/flatten-maven-plugin/ +[36]: https://sonatype.github.io/ossindex-maven/maven-plugin/ +[37]: https://maven.apache.org/surefire/maven-surefire-plugin/ +[38]: https://www.mojohaus.org/versions/versions-maven-plugin/ +[39]: https://basepom.github.io/duplicate-finder-maven-plugin +[40]: http://www.apache.org/licenses/LICENSE-2.0.html +[41]: https://maven.apache.org/plugins/maven-assembly-plugin/ +[42]: https://maven.apache.org/plugins/maven-jar-plugin/ +[43]: https://github.com/exasol/artifact-reference-checker-maven-plugin/ +[44]: https://github.com/exasol/artifact-reference-checker-maven-plugin/blob/main/LICENSE +[45]: https://github.com/exasol/project-keeper/ +[46]: https://github.com/exasol/project-keeper/blob/main/LICENSE +[47]: https://maven.apache.org/plugins/maven-dependency-plugin/ +[48]: https://www.mojohaus.org/exec-maven-plugin +[49]: https://maven.apache.org/surefire/maven-failsafe-plugin/ +[50]: https://www.jacoco.org/jacoco/trunk/doc/maven.html +[51]: https://github.com/exasol/error-code-crawler-maven-plugin/ +[52]: https://github.com/exasol/error-code-crawler-maven-plugin/blob/main/LICENSE +[53]: http://zlika.github.io/reproducible-build-maven-plugin diff --git a/doc/changes/changelog.md b/doc/changes/changelog.md new file mode 100644 index 0000000..9e62d07 --- /dev/null +++ b/doc/changes/changelog.md @@ -0,0 +1,3 @@ +# Changes + +* [0.1.0](changes_0.1.0.md) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md new file mode 100644 index 0000000..59e0a4b --- /dev/null +++ b/doc/changes/changes_0.1.0.md @@ -0,0 +1,60 @@ +# Virtual Schema for Snowflake 0.1.0, released 2020-11-18 + +Code name: First version + +## Summary + +## Features / Enhancements + +* #1: SomethingSomething #TO DO +## Dependency Updates + +### Compile Dependency Updates + +* Added `com.exasol:error-reporting-java:1.0.1` +* Added `com.exasol:virtual-schema-common-jdbc:12.0.0` +* Added `net.snowflake:snowflake-jdbc:3.16.1` + +### Test Dependency Updates + +* Added `com.exasol:autogenerated-resource-verifier-java:0.1.2` +* Added `com.exasol:exasol-testcontainers:7.0.1` +* Added `com.exasol:hamcrest-resultset-matcher:1.6.4` +* Added `com.exasol:test-db-builder-java:3.5.3` +* Added `com.exasol:udf-debugging-java:0.6.11` +* Added `com.exasol:virtual-schema-common-jdbc:12.0.0` +* Added `com.exasol:virtual-schema-shared-integration-tests:3.0.0` +* Added `net.steppschuh.markdowngenerator:markdowngenerator:1.3.1.1` +* Added `org.hamcrest:hamcrest:2.2` +* Added `org.jacoco:org.jacoco.agent:0.8.12` +* Added `org.junit.jupiter:junit-jupiter:5.10.1` +* Added `org.mockito:mockito-junit-jupiter:5.10.0` +* Added `org.testcontainers:junit-jupiter:1.19.4` +* Added `org.testcontainers:localstack:1.19.8` + +### Plugin Dependency Updates + +* Added `com.exasol:artifact-reference-checker-maven-plugin:0.4.2` +* Added `com.exasol:error-code-crawler-maven-plugin:2.0.3` +* Added `com.exasol:project-keeper-maven-plugin:4.3.3` +* Added `io.github.zlika:reproducible-build-maven-plugin:0.16` +* Added `org.apache.maven.plugins:maven-assembly-plugin:3.7.1` +* Added `org.apache.maven.plugins:maven-clean-plugin:3.2.0` +* Added `org.apache.maven.plugins:maven-compiler-plugin:3.13.0` +* Added `org.apache.maven.plugins:maven-dependency-plugin:3.6.1` +* Added `org.apache.maven.plugins:maven-deploy-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-enforcer-plugin:3.5.0` +* Added `org.apache.maven.plugins:maven-failsafe-plugin:3.2.5` +* Added `org.apache.maven.plugins:maven-install-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-jar-plugin:3.4.1` +* Added `org.apache.maven.plugins:maven-resources-plugin:3.3.1` +* Added `org.apache.maven.plugins:maven-site-plugin:3.12.1` +* Added `org.apache.maven.plugins:maven-surefire-plugin:3.2.5` +* Added `org.apache.maven.plugins:maven-toolchains-plugin:3.2.0` +* Added `org.basepom.maven:duplicate-finder-maven-plugin:2.0.1` +* Added `org.codehaus.mojo:exec-maven-plugin:3.1.0` +* Added `org.codehaus.mojo:flatten-maven-plugin:1.6.0` +* Added `org.codehaus.mojo:versions-maven-plugin:2.16.2` +* Added `org.jacoco:jacoco-maven-plugin:0.8.12` +* Added `org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121` +* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` diff --git a/doc/design.md b/doc/design.md new file mode 100644 index 0000000..49a8da2 --- /dev/null +++ b/doc/design.md @@ -0,0 +1 @@ +# Design for the Snowflake Virtual Schema adapter \ No newline at end of file diff --git a/doc/developers_guide/developers_guide.md b/doc/developers_guide/developers_guide.md new file mode 100644 index 0000000..1c2e6d2 --- /dev/null +++ b/doc/developers_guide/developers_guide.md @@ -0,0 +1,3 @@ +# Developers Guide + + diff --git a/doc/generated/capabilities.md b/doc/generated/capabilities.md new file mode 100644 index 0000000..230d986 --- /dev/null +++ b/doc/generated/capabilities.md @@ -0,0 +1,307 @@ + + +# Capabilities + +Capabilities tell the Exasol which SQL features / keywords a Virtual Schema adapter supports. If the Virtual Schema does not support a certain capability, Exasol rewrites the query without that feature. In case a Virtual Schema adapter has no capabilities at all, Exasol will rewrite all queries to `SELECT * FROM table`. That means, that it will always load the whole remote table, even if only a single row is requested.So, for optimizing your performance, make sure that at least all functions that you use in the `WHERE` clause of your queries are supported by the Virtual Schema adapter. + +## Main Capabilities + +| Capability | Supported | +| ----------------------------- |:---------:| +| SELECTLIST_PROJECTION | ✓ | +| SELECTLIST_EXPRESSIONS | ✓ | +| FILTER_EXPRESSIONS | ✓ | +| AGGREGATE_SINGLE_GROUP | ✓ | +| AGGREGATE_GROUP_BY_COLUMN | ✓ | +| AGGREGATE_GROUP_BY_EXPRESSION | ✓ | +| AGGREGATE_GROUP_BY_TUPLE | ✓ | +| AGGREGATE_HAVING | ✓ | +| ORDER_BY_COLUMN | ✓ | +| ORDER_BY_EXPRESSION | ✓ | +| LIMIT | ✓ | +| LIMIT_WITH_OFFSET | ✓ | +| JOIN | ✓ | +| JOIN_TYPE_INNER | ✓ | +| JOIN_TYPE_LEFT_OUTER | ✓ | +| JOIN_TYPE_RIGHT_OUTER | ✓ | +| JOIN_TYPE_FULL_OUTER | ✓ | +| JOIN_CONDITION_EQUI | ✓ | +| JOIN_CONDITION_ALL | | + +## Supported Literals + +| Literal | Supported | +| ------------- |:---------:| +| NULL | ✓ | +| BOOL | ✓ | +| DATE | ✓ | +| TIMESTAMP | ✓ | +| TIMESTAMP_UTC | ✓ | +| DOUBLE | ✓ | +| EXACTNUMERIC | ✓ | +| STRING | ✓ | +| INTERVAL | | + +## Supported Predicates + +| Predicate | Supported | +| ------------ |:---------:| +| AND | ✓ | +| OR | ✓ | +| NOT | ✓ | +| EQUAL | ✓ | +| NOTEQUAL | ✓ | +| LESS | ✓ | +| LESSEQUAL | ✓ | +| LIKE | ✓ | +| LIKE_ESCAPE | ✓ | +| REGEXP_LIKE | ✓ | +| BETWEEN | ✓ | +| IN_CONSTLIST | ✓ | +| IS_NULL | ✓ | +| IS_NOT_NULL | ✓ | +| IS_JSON | | +| IS_NOT_JSON | | + +## Supported Aggregate Functions + +| Aggregate Function | Supported | +| ---------------------------- |:---------:| +| COUNT | ✓ | +| COUNT_STAR | ✓ | +| COUNT_DISTINCT | ✓ | +| COUNT_TUPLE | | +| SUM | ✓ | +| SUM_DISTINCT | ✓ | +| MIN | ✓ | +| MAX | ✓ | +| AVG | ✓ | +| AVG_DISTINCT | ✓ | +| MEDIAN | ✓ | +| FIRST_VALUE | ✓ | +| LAST_VALUE | ✓ | +| STDDEV | ✓ | +| STDDEV_DISTINCT | ✓ | +| STDDEV_POP | ✓ | +| STDDEV_POP_DISTINCT | ✓ | +| STDDEV_SAMP | ✓ | +| STDDEV_SAMP_DISTINCT | ✓ | +| VARIANCE | ✓ | +| VARIANCE_DISTINCT | ✓ | +| VAR_POP | ✓ | +| VAR_POP_DISTINCT | ✓ | +| VAR_SAMP | ✓ | +| VAR_SAMP_DISTINCT | ✓ | +| GROUP_CONCAT | ✓ | +| GROUP_CONCAT_DISTINCT | | +| GROUP_CONCAT_SEPARATOR | | +| GROUP_CONCAT_ORDER_BY | | +| GEO_INTERSECTION_AGGREGATE | | +| GEO_UNION_AGGREGATE | | +| ST_INTERSECTION | | +| ST_UNION | | +| APPROXIMATE_COUNT_DISTINCT | | +| MUL | | +| MUL_DISTINCT | | +| EVERY | | +| SOME | | +| LISTAGG | | +| LISTAGG_DISTINCT | | +| LISTAGG_SEPARATOR | | +| LISTAGG_ON_OVERFLOW_ERROR | | +| LISTAGG_ON_OVERFLOW_TRUNCATE | | +| LISTAGG_ORDER_BY | | + +## Supported Scalar Functions + +| Scalar Function | Supported | +| ------------------- |:---------:| +| ADD | ✓ | +| SUB | ✓ | +| MULT | ✓ | +| FLOAT_DIV | ✓ | +| NEG | ✓ | +| ABS | ✓ | +| ACOS | ✓ | +| ASIN | ✓ | +| ATAN | ✓ | +| ATAN2 | ✓ | +| CEIL | ✓ | +| COS | ✓ | +| COSH | ✓ | +| COT | ✓ | +| DEGREES | ✓ | +| DIV | ✓ | +| EXP | ✓ | +| FLOOR | ✓ | +| GREATEST | ✓ | +| LEAST | ✓ | +| LN | ✓ | +| LOG | ✓ | +| MOD | ✓ | +| POWER | ✓ | +| RADIANS | ✓ | +| RAND | ✓ | +| ROUND | | +| SIGN | ✓ | +| SIN | ✓ | +| SINH | ✓ | +| SQRT | ✓ | +| TAN | ✓ | +| TANH | ✓ | +| TRUNC | ✓ | +| ASCII | ✓ | +| BIT_LENGTH | ✓ | +| CHR | ✓ | +| COLOGNE_PHONETIC | | +| CONCAT | | +| DUMP | | +| EDIT_DISTANCE | | +| INITCAP | ✓ | +| INSERT | | +| INSTR | | +| LENGTH | ✓ | +| LOCATE | | +| LOWER | ✓ | +| LPAD | ✓ | +| LTRIM | ✓ | +| OCTET_LENGTH | ✓ | +| REGEXP_INSTR | | +| REGEXP_REPLACE | ✓ | +| REGEXP_SUBSTR | | +| REPEAT | ✓ | +| REPLACE | ✓ | +| REVERSE | ✓ | +| RIGHT | ✓ | +| RPAD | ✓ | +| RTRIM | ✓ | +| SOUNDEX | | +| SPACE | | +| SUBSTR | ✓ | +| TRANSLATE | ✓ | +| TRIM | ✓ | +| UNICODE | | +| UNICODECHR | | +| UPPER | ✓ | +| ADD_DAYS | ✓ | +| ADD_HOURS | ✓ | +| ADD_MINUTES | ✓ | +| ADD_MONTHS | ✓ | +| ADD_SECONDS | ✓ | +| ADD_WEEKS | ✓ | +| ADD_YEARS | ✓ | +| CONVERT_TZ | | +| CURRENT_DATE | ✓ | +| CURRENT_TIMESTAMP | ✓ | +| DATE_TRUNC | ✓ | +| DAY | ✓ | +| DAYS_BETWEEN | | +| DBTIMEZONE | | +| EXTRACT | ✓ | +| FROM_POSIX_TIME | | +| HOUR | | +| HOURS_BETWEEN | | +| LOCALTIMESTAMP | ✓ | +| MINUTE | ✓ | +| MINUTES_BETWEEN | | +| MONTH | ✓ | +| MONTHS_BETWEEN | | +| NUMTODSINTERVAL | | +| NUMTOYMINTERVAL | | +| POSIX_TIME | | +| SECOND | | +| SECONDS_BETWEEN | | +| SESSIONTIMEZONE | | +| SYSDATE | | +| SYSTIMESTAMP | | +| WEEK | ✓ | +| YEAR | ✓ | +| YEARS_BETWEEN | | +| ST_X | | +| ST_Y | | +| ST_ENDPOINT | | +| ST_ISCLOSED | | +| ST_ISRING | | +| ST_LENGTH | | +| ST_NUMPOINTS | | +| ST_POINTN | | +| ST_STARTPOINT | | +| ST_AREA | | +| ST_EXTERIORRING | | +| ST_INTERIORRINGN | | +| ST_NUMINTERIORRINGS | | +| ST_GEOMETRYN | | +| ST_NUMGEOMETRIES | | +| ST_BOUNDARY | | +| ST_BUFFER | | +| ST_CENTROID | | +| ST_CONTAINS | | +| ST_CONVEXHULL | | +| ST_CROSSES | | +| ST_DIFFERENCE | | +| ST_DIMENSION | | +| ST_DISJOINT | | +| ST_DISTANCE | | +| ST_ENVELOPE | | +| ST_EQUALS | | +| ST_FORCE2D | | +| ST_GEOMETRYTYPE | | +| ST_INTERSECTION | | +| ST_INTERSECTS | | +| ST_ISEMPTY | | +| ST_ISSIMPLE | | +| ST_OVERLAPS | | +| ST_SETSRID | | +| ST_SYMDIFFERENCE | | +| ST_TOUCHES | | +| ST_TRANSFORM | | +| ST_UNION | | +| ST_WITHIN | | +| CAST | | +| IS_NUMBER | | +| IS_BOOLEAN | | +| IS_DATE | | +| IS_DSINTERVAL | | +| IS_YMINTERVAL | | +| IS_TIMESTAMP | | +| TO_CHAR | | +| TO_DATE | | +| TO_DSINTERVAL | | +| TO_YMINTERVAL | | +| TO_NUMBER | | +| TO_TIMESTAMP | | +| BIT_AND | | +| BIT_CHECK | | +| BIT_LROTATE | | +| BIT_LSHIFT | | +| BIT_NOT | | +| BIT_OR | | +| BIT_RROTATE | | +| BIT_RSHIFT | | +| BIT_SET | | +| BIT_TO_NUM | | +| BIT_XOR | | +| CASE | ✓ | +| CURRENT_SCHEMA | ✓ | +| CURRENT_SESSION | | +| CURRENT_STATEMENT | | +| CURRENT_USER | | +| HASH_MD5 | ✓ | +| HASHTYPE_MD5 | | +| HASH_SHA1 | | +| HASHTYPE_SHA1 | | +| HASH_SHA256 | | +| HASHTYPE_SHA256 | | +| HASH_SHA512 | | +| HASHTYPE_SHA512 | | +| HASH_TIGER | | +| HASHTYPE_TIGER | | +| NULLIFZERO | | +| SYS_GUID | | +| ZEROIFNULL | | +| JSON_VALUE | | +| SESSION_PARAMETER | ✓ | +| MIN_SCALE | | +| TYPEOF | ✓ | +| CURRENT_CLUSTER | ✓ | + diff --git a/doc/user_guide/snowflake_user_guide.md b/doc/user_guide/snowflake_user_guide.md new file mode 100644 index 0000000..e69de29 diff --git a/error_code_config.yml b/error_code_config.yml new file mode 100644 index 0000000..08ef8cc --- /dev/null +++ b/error_code_config.yml @@ -0,0 +1,5 @@ +error-tags: + VSSF: + packages: + - com.exasol.closeafterall + highest-index: 9 diff --git a/pk_generated_parent.pom b/pk_generated_parent.pom new file mode 100644 index 0000000..eeaf0cf --- /dev/null +++ b/pk_generated_parent.pom @@ -0,0 +1,380 @@ + + + 4.0.0 + com.exasol + snowflake-virtual-schema-generated-parent + 0.1.0 + pom + + UTF-8 + UTF-8 + 11 + exasol + https://sonarcloud.io + + + + + MIT License + https://github.com/exasol/snowflake-virtual-schema/blob/main/LICENSE + repo + + + + + Exasol + opensource@exasol.com + Exasol AG + https://www.exasol.com/ + + + + scm:git:https://github.com/exasol/snowflake-virtual-schema.git + scm:git:https://github.com/exasol/snowflake-virtual-schema.git + https://github.com/exasol/snowflake-virtual-schema/ + + + + org.jacoco + org.jacoco.agent + 0.8.12 + test + runtime + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 4.0.0.4121 + + + org.apache.maven.plugins + maven-toolchains-plugin + 3.2.0 + + + + toolchain + + + + + + + ${java.version} + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${java.version} + ${java.version} + true + + -Xlint:all + -Werror + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.5.0 + + + enforce-maven + + enforce + + + + + 3.6.3 + + + 17 + + + + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.6.0 + + true + oss + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + org.sonatype.ossindex.maven + ossindex-maven-plugin + 3.2.0 + + + audit + package + + audit + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.2.5 + + + -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} + ${test.excludeTags} + + + + org.codehaus.mojo + versions-maven-plugin + 2.16.2 + + + display-updates + package + + display-plugin-updates + display-dependency-updates + + + + + file:///${project.basedir}/versionsMavenPluginRules.xml + false + true + true + true + false + true + true + true + false + true + true + + + + org.basepom.maven + duplicate-finder-maven-plugin + 2.0.1 + + + default + verify + + check + + + + + true + true + true + true + true + true + false + true + false + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.7.1 + + + src/assembly/all-dependencies.xml + + NAME_OF_YOUR_JAR + false + + + true + + + + + + make-assembly + package + + single + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.4.1 + + + default-jar + none + + + + + com.exasol + artifact-reference-checker-maven-plugin + 0.4.2 + + + verify + + verify + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.6.1 + + + copy-jacoco + + copy-dependencies + + compile + + org.jacoco.agent + runtime + ${project.build.directory}/jacoco-agent + true + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.2.5 + + + -Djava.util.logging.config.file=src/test/resources/logging.properties ${argLine} + + true + + ${test.excludeTags} + + + + verify + + integration-test + verify + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.12 + + + prepare-agent + + prepare-agent + + + + prepare-agent-integration + + prepare-agent-integration + + + + merge-results + verify + + merge + + + + + ${project.build.directory}/ + + jacoco*.exec + + + + ${project.build.directory}/aggregate.exec + + + + report + verify + + report + + + ${project.build.directory}/aggregate.exec + + + + + + com.exasol + error-code-crawler-maven-plugin + 2.0.3 + + + verify + + verify + + + + + + io.github.zlika + reproducible-build-maven-plugin + 0.16 + + + strip-jar + package + + strip-jar + + + + + + + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..e32d619 --- /dev/null +++ b/pom.xml @@ -0,0 +1,190 @@ + + + 4.0.0 + snowflake-virtual-schema + 0.1.0 + Virtual Schema for Snowflake + Virtual Schema for connecting Snowflake as data source to Exasol + https://github.com/exasol/snowflake-virtual-schema/ + + 12.0.0 + 1.19.4 + + + + com.exasol + virtual-schema-common-jdbc + ${vscjdbc.version} + + + com.exasol + error-reporting-java + 1.0.1 + + + net.snowflake + snowflake-jdbc + 3.16.1 + + + + com.exasol + virtual-schema-common-jdbc + ${vscjdbc.version} + test-jar + test + + + org.hamcrest + hamcrest + 2.2 + test + + + org.junit.jupiter + junit-jupiter + 5.10.1 + test + + + org.mockito + mockito-junit-jupiter + 5.10.0 + test + + + + com.exasol + exasol-testcontainers + 7.0.1 + test + + + org.testcontainers + junit-jupiter + ${org.testcontainers.version} + test + + + org.testcontainers + localstack + 1.19.8 + test + + + com.exasol + test-db-builder-java + 3.5.3 + test + + + com.exasol + hamcrest-resultset-matcher + 1.6.4 + test + + + com.exasol + udf-debugging-java + 0.6.11 + test + + + net.steppschuh.markdowngenerator + markdowngenerator + 1.3.1.1 + test + + + com.exasol + autogenerated-resource-verifier-java + 0.1.2 + test + + + com.exasol + virtual-schema-shared-integration-tests + 3.0.0 + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + virtual-schema-dist-${vscjdbc.version}-snowflake-${project.version} + + + + com.exasol + project-keeper-maven-plugin + 4.3.3 + + + + verify + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-snowflake-driver + + copy-dependencies + + compile + + net.snowflake + snowflake-jdbc + ${project.build.directory}/snowflake-driver + true + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + validate-capabilities-report + + java + + package + + com.exasol.adapter.dialects.snowflake.docgeneration.SnowflakeAutogeneratedResourceVerifier + test + + + projectDir + ${project.basedir} + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + false + + + + + + snowflake-virtual-schema-generated-parent + com.exasol + 0.1.0 + pk_generated_parent.pom + + diff --git a/src/assembly/all-dependencies.xml b/src/assembly/all-dependencies.xml new file mode 100644 index 0000000..efe5abc --- /dev/null +++ b/src/assembly/all-dependencies.xml @@ -0,0 +1,22 @@ + + all-dependencies + + jar + + false + + + + metaInf-services + + + + + true + runtime + / + + + diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java new file mode 100644 index 0000000..ac24cb1 --- /dev/null +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java @@ -0,0 +1,89 @@ +package com.exasol.adapter.dialects.snowflake; + +import java.sql.*; +import java.util.logging.Logger; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.IdentifierConverter; +//import com.exasol.adapter.dialects.snowflake.SnowflakeIdentifierMapping.CaseFolding; +import com.exasol.adapter.jdbc.BaseColumnMetadataReader; +import com.exasol.adapter.jdbc.JDBCTypeDescription; +import com.exasol.adapter.metadata.DataType; + +/** + * This class implements Snowflake-specific reading of column metadata. + */ +public class SnowflakeColumnMetadataReader extends BaseColumnMetadataReader { + private static final Logger LOGGER = Logger.getLogger(SnowflakeColumnMetadataReader.class.getName()); + private static final String SNOWFLAKE_VARBIT_TYPE_NAME = "varbit"; + + /** + * Create a new instance of the {@link SnowflakeColumnMetadataReader}. + * + * @param connection JDBC connection to the remote data source + * @param properties user-defined adapter properties + * @param identifierConverter converter between source and Exasol identifiers + */ + public SnowflakeColumnMetadataReader(final Connection connection, final AdapterProperties properties, + final IdentifierConverter identifierConverter) { + super(connection, properties, identifierConverter); + } + + /** + * Get the catalog name that is applied as filter criteria when looking up remote metadata. + * + * @return catalog name or null if metadata lookups are not limited by catalog + */ +// @Override +// public String getCatalogNameFilter() { +// return this.properties.getDatabaseName(); +// } + @Override + public DataType mapJdbcType(final JDBCTypeDescription jdbcTypeDescription) { + switch (jdbcTypeDescription.getJdbcType()) { + case Types.OTHER: + return mapJdbcTypeOther(jdbcTypeDescription); + case Types.SQLXML: + case Types.DISTINCT: + case Types.BINARY: + return DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8); + default: + return super.mapJdbcType(jdbcTypeDescription); + } + } + + protected DataType mapJdbcTypeOther(final JDBCTypeDescription jdbcTypeDescription) { + if (isVarBitColumn(jdbcTypeDescription)) { + final int n = jdbcTypeDescription.getPrecisionOrSize(); + LOGGER.finer(() -> "Mapping Snowflake datatype \"OTHER:varbit\" to VARCHAR(" + n + ")"); + return DataType.createVarChar(n, DataType.ExaCharset.UTF8); + } else { + LOGGER.finer(() -> "Mapping Snowflake datatype \"" + jdbcTypeDescription.getTypeName() + + "\" to maximum VARCHAR()"); + return DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8); + } + } + + protected boolean isVarBitColumn(final JDBCTypeDescription jdbcTypeDescription) { + return jdbcTypeDescription.getTypeName().equals(SNOWFLAKE_VARBIT_TYPE_NAME); + } + + @Override + public String readColumnName(final ResultSet columns) throws SQLException { +// if (getIdentifierMapping().equals(CaseFolding.CONVERT_TO_UPPER)) { +// return super.readColumnName(columns).toUpperCase(); +// } else { + return super.readColumnName(columns); +// } + } + + @Override + public String getSchemaNameFilter() { + return this.properties.getSchemaName().toUpperCase(); + //return this.properties.getSchemaName().replace("_","\\_").toUpperCase(); + } + +// CaseFolding getIdentifierMapping() { +// return SnowflakeIdentifierMapping.from(this.properties); +// } +} \ No newline at end of file diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java new file mode 100644 index 0000000..e323fdd --- /dev/null +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java @@ -0,0 +1,45 @@ +package com.exasol.adapter.dialects.snowflake; + +import java.sql.Connection; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.BaseIdentifierConverter; +import com.exasol.adapter.dialects.IdentifierConverter; +import com.exasol.adapter.jdbc.*; + +/** + * This class implements a reader for Snowflake-specific metadata. + */ +public class SnowflakeMetadataReader extends AbstractRemoteMetadataReader { + /** + * Create a new instance of the {@link SnowflakeMetadataReader}. + * + * @param connection connection to the Snowflake database + * @param properties user-defined adapter properties + */ + public SnowflakeMetadataReader(final Connection connection, final AdapterProperties properties) { + super(connection, properties); + } + + @Override + public BaseTableMetadataReader createTableMetadataReader() { + return new SnowflakeTableMetadataReader(this.connection, getColumnMetadataReader(), this.properties, + getIdentifierConverter()); + } + + @Override + protected IdentifierConverter createIdentifierConverter() { + return BaseIdentifierConverter.createDefault(); + } + + @Override + public ColumnMetadataReader createColumnMetadataReader() { + return new SnowflakeColumnMetadataReader(this.connection, this.properties, getIdentifierConverter()); + } + + @Override + public String getSchemaNameFilter() { + return this.properties.getSchemaName().replace("_","\\_").toUpperCase(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java new file mode 100644 index 0000000..b69d138 --- /dev/null +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java @@ -0,0 +1,196 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.adapter.AdapterProperties.*; +import static com.exasol.adapter.capabilities.AggregateFunctionCapability.*; +import static com.exasol.adapter.capabilities.LiteralCapability.*; +import static com.exasol.adapter.capabilities.MainCapability.*; +import static com.exasol.adapter.capabilities.PredicateCapability.*; +import static com.exasol.adapter.capabilities.ScalarFunctionCapability.*; +import static com.exasol.adapter.capabilities.ScalarFunctionCapability.ST_INTERSECTION; +import static com.exasol.adapter.capabilities.ScalarFunctionCapability.ST_UNION; + +import java.sql.SQLException; +import java.util.*; +import java.util.function.Predicate; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.capabilities.Capabilities; +import com.exasol.adapter.capabilities.ScalarFunctionCapability; +import com.exasol.adapter.dialects.*; +import com.exasol.adapter.dialects.rewriting.ImportIntoTemporaryTableQueryRewriter; +import com.exasol.adapter.dialects.rewriting.SqlGenerationContext; +import com.exasol.adapter.jdbc.*; +import com.exasol.adapter.sql.ScalarFunction; +import com.exasol.errorreporting.ExaError; + +/** + * This class implements the Snowflake dialect. + */ +public class SnowflakeSqlDialect extends AbstractSqlDialect { + static final String NAME = "SNOWFLAKE"; + + private static final Set DISABLED_SCALAR_FUNCTION = Set.of( + /* + * Implementation for `BETWEEN` time functions is not supported. For more information see `design.md` file, + * `Scalar Functions` section + */ + SECONDS_BETWEEN, MINUTES_BETWEEN, HOURS_BETWEEN, DAYS_BETWEEN, MONTHS_BETWEEN, YEARS_BETWEEN, // + ROUND, // Snowflake rounds `0.5` down while Exasol rounds it up + SECOND, // It presents precision issues + COLOGNE_PHONETIC, // No Snowflake equivalent + CONCAT, // It fails for boolean data types + INSTR, // not implemented; probably possible using strpos + POSIX_TIME, // Does not follow Exasol session timezone + // Currently not implemented: + DUMP, EDIT_DISTANCE, INSERT, LOCATE, REGEXP_INSTR, REGEXP_SUBSTR, SOUNDEX, SPACE, UNICODE, UNICODECHR, + DBTIMEZONE, FROM_POSIX_TIME, HOUR, SESSIONTIMEZONE, IS_NUMBER, IS_BOOLEAN, IS_DATE, IS_DSINTERVAL, + IS_YMINTERVAL, IS_TIMESTAMP, TO_CHAR, TO_DATE, TO_NUMBER, TO_TIMESTAMP, BIT_AND, BIT_CHECK, BIT_LROTATE, + BIT_LSHIFT, BIT_NOT, BIT_OR, BIT_RROTATE, BIT_RSHIFT, BIT_SET, BIT_TO_NUM, BIT_XOR, HASHTYPE_MD5, HASH_SHA1, + HASHTYPE_SHA1, HASH_SHA256, HASHTYPE_SHA256, HASH_SHA512, HASHTYPE_SHA512, HASH_TIGER, HASHTYPE_TIGER, + NULLIFZERO, ZEROIFNULL, MIN_SCALE, NUMTOYMINTERVAL, JSON_VALUE, TO_DSINTERVAL, CONVERT_TZ, NUMTODSINTERVAL, + TO_YMINTERVAL, CAST, SYS_GUID, SYSTIMESTAMP, CURRENT_STATEMENT, CURRENT_USER, SYSDATE, CURRENT_SESSION, // + // Geospatial are currently not supported: + ST_X, ST_Y, ST_ENDPOINT, ST_ISCLOSED, ST_ISRING, ST_LENGTH, ST_NUMPOINTS, ST_POINTN, ST_STARTPOINT, ST_AREA, + ST_EXTERIORRING, ST_INTERIORRINGN, ST_NUMINTERIORRINGS, ST_GEOMETRYN, ST_NUMGEOMETRIES, ST_BOUNDARY, + ST_BUFFER, ST_CENTROID, ST_CONTAINS, ST_CONVEXHULL, ST_CROSSES, ST_DIFFERENCE, ST_DIMENSION, ST_DISJOINT, + ST_DISTANCE, ST_ENVELOPE, ST_EQUALS, ST_FORCE2D, ST_GEOMETRYTYPE, ST_INTERSECTION, ST_INTERSECTS, + ST_ISEMPTY, ST_ISSIMPLE, ST_OVERLAPS, ST_SETSRID, ST_SYMDIFFERENCE, ST_TOUCHES, ST_TRANSFORM, ST_UNION, + ST_WITHIN); + private static final Capabilities CAPABILITIES = createCapabilityList(); + static final String DATABASE_NAME_PROPERTY = "DATABASE_NAME"; + static final String ACCOUNT_NAME_PROPERTY = "ACCOUNT_NAME"; + + /* + * IMPORTANT! Before adding new capabilities, check the `doc/design.md` file if there is a note on why the + * capability is not supported. it. + */ + private static Capabilities createCapabilityList() { + return Capabilities.builder() + .addMain(SELECTLIST_PROJECTION, SELECTLIST_EXPRESSIONS, FILTER_EXPRESSIONS, AGGREGATE_SINGLE_GROUP, + AGGREGATE_GROUP_BY_COLUMN, AGGREGATE_GROUP_BY_EXPRESSION, AGGREGATE_GROUP_BY_TUPLE, + AGGREGATE_HAVING, ORDER_BY_COLUMN, ORDER_BY_EXPRESSION, LIMIT, LIMIT_WITH_OFFSET, JOIN, + JOIN_TYPE_INNER, JOIN_TYPE_LEFT_OUTER, JOIN_TYPE_RIGHT_OUTER, JOIN_TYPE_FULL_OUTER, + JOIN_CONDITION_EQUI) + .addPredicate(AND, OR, NOT, EQUAL, NOTEQUAL, LESS, LESSEQUAL, LIKE, LIKE_ESCAPE, BETWEEN, REGEXP_LIKE, + IN_CONSTLIST, IS_NULL, IS_NOT_NULL) + .addLiteral(BOOL, NULL, DATE, TIMESTAMP, TIMESTAMP_UTC, DOUBLE, EXACTNUMERIC, STRING) + .addAggregateFunction(COUNT, COUNT_STAR, COUNT_DISTINCT, SUM, SUM_DISTINCT, MIN, MAX, AVG, AVG_DISTINCT, + MEDIAN, FIRST_VALUE, LAST_VALUE, STDDEV, STDDEV_DISTINCT, STDDEV_POP, STDDEV_POP_DISTINCT, + STDDEV_SAMP, STDDEV_SAMP_DISTINCT, VARIANCE, VARIANCE_DISTINCT, VAR_POP, VAR_POP_DISTINCT, + VAR_SAMP, VAR_SAMP_DISTINCT, GROUP_CONCAT) + .addScalarFunction(getEnabledScalarFunctionCapabilities()).build(); + } + + /** + * This class gets all {@link ScalarFunctionCapability}s that are not explicitly excluded by + * {@link #DISABLED_SCALAR_FUNCTION}. + * + * @return list enabled scalar function capabilities + */ + private static ScalarFunctionCapability[] getEnabledScalarFunctionCapabilities() { + return Arrays.stream(ScalarFunctionCapability.values()) + .filter(Predicate.not(DISABLED_SCALAR_FUNCTION::contains)).toArray(ScalarFunctionCapability[]::new); + } + + /** + * Create a new instance of the {@link SnowflakeSqlDialect}. + * + * @param connectionFactory factory for the JDBC connection to the remote data source + * @param properties user-defined adapter properties + */ + public SnowflakeSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) { + super(connectionFactory, properties, // + //Set.of(SCHEMA_NAME_PROPERTY, DATABASE_NAME_PROPERTY, ACCOUNT_NAME_PROPERTY), // + Set.of(SCHEMA_NAME_PROPERTY, CATALOG_NAME_PROPERTY, ACCOUNT_NAME_PROPERTY), // + List.of()); + } + + @Override + public String getName() { + return NAME; + } + + @Override + protected RemoteMetadataReader createRemoteMetadataReader() { + try { + return new SnowflakeMetadataReader(this.connectionFactory.getConnection(), this.properties); + } catch (final SQLException exception) { + throw new RemoteMetadataReaderException(ExaError.messageBuilder("E-VSSF-3") + .message("Unable to create Snowflake remote metadata reader. Caused by: {{cause}}", + exception.getMessage()) + .toString(), exception); + } + } + + @Override + protected QueryRewriter createQueryRewriter() { + return new ImportIntoTemporaryTableQueryRewriter(this, createRemoteMetadataReader(), this.connectionFactory); + } + + @Override + public boolean omitParentheses(final ScalarFunction function) { + return function.name().equals("CURRENT_DATE") || function.name().equals("CURRENT_TIMESTAMP") + || function.name().equals("LOCALTIMESTAMP"); + } + + @Override + public Capabilities getCapabilities() { + return CAPABILITIES; + } + + @Override + public Map getScalarFunctionAliases() { + final Map scalarAliases = new EnumMap<>(ScalarFunction.class); + scalarAliases.put(ScalarFunction.SUBSTR, "SUBSTRING"); + scalarAliases.put(ScalarFunction.HASH_MD5, "MD5"); + scalarAliases.put(ScalarFunction.RAND, "RANDOM"); + return scalarAliases; + } + + @Override + public StructureElementSupport supportsJdbcCatalogs() { + return StructureElementSupport.MULTIPLE; + } + + @Override + public StructureElementSupport supportsJdbcSchemas() { + return StructureElementSupport.MULTIPLE; + } + + @Override + public String applyQuote(String identifier) { + return super.quoteIdentifierWithDoubleQuotes(identifier); + } + + + @Override + public boolean requiresCatalogQualifiedTableNames(final SqlGenerationContext context) { + return true; + } + + @Override + public boolean requiresSchemaQualifiedTableNames(final SqlGenerationContext context) { + return true; + } + + @Override + public NullSorting getDefaultNullSorting() { + return NullSorting.NULLS_SORTED_AT_END; + } + + @Override + public SqlGenerator getSqlGenerator(final SqlGenerationContext context) { + return new SnowflakeSqlGenerationVisitor(this, context); + } + + @Override + + public String getStringLiteral(final String value) { + if (value == null) { + return "NULL"; + } + // We use an escape string constant to be independent of the parameter standard_conforming_strings. + // We use '' instead of \' to be independent of the parameter backslash_quote. + return "E'" + value.replace("\\", "\\\\").replace("'", "''") + "'"; + } +} diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java new file mode 100644 index 0000000..1f4db40 --- /dev/null +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java @@ -0,0 +1,30 @@ +package com.exasol.adapter.dialects.snowflake; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.SqlDialect; +import com.exasol.adapter.dialects.SqlDialectFactory; +import com.exasol.adapter.jdbc.ConnectionFactory; +import com.exasol.logging.VersionCollector; + +/** + * Factory for the Snowflake SQL dialect. + */ +public class SnowflakeSqlDialectFactory implements SqlDialectFactory { + + @Override + public String getSqlDialectName() { + return SnowflakeSqlDialect.NAME; + } + + @Override + public SqlDialect createSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) { + return new SnowflakeSqlDialect(connectionFactory, properties); + } + + @Override + public String getSqlDialectVersion() { + final VersionCollector versionCollector = new VersionCollector( + "META-INF/maven/com.exasol/virtual-schema-jdbc-adapter/pom.properties"); + return versionCollector.getVersionNumber(); + } +} \ No newline at end of file diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java new file mode 100644 index 0000000..7d48a29 --- /dev/null +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java @@ -0,0 +1,206 @@ +package com.exasol.adapter.dialects.snowflake; + +import java.util.*; + +import com.exasol.adapter.AdapterException; +import com.exasol.adapter.dialects.SqlDialect; +import com.exasol.adapter.dialects.rewriting.SqlGenerationContext; +import com.exasol.adapter.dialects.rewriting.SqlGenerationVisitor; +import com.exasol.adapter.sql.*; + +/** + * This class generates SQL queries for the {@link SnowflakeSqlDialect}. + */ +public class SnowflakeSqlGenerationVisitor extends SqlGenerationVisitor { + private static final List TYPE_NAMES_REQUIRING_CAST = List.of("varbit", "point", "line", "lseg", "box", + "path", "polygon", "circle", "cidr", "citext", "inet", "macaddr", "interval", "json", "jsonb", "uuid", + "tsquery", "tsvector", "xml", "smallserial", "serial", "bigserial"); + private static final List TYPE_NAMES_NOT_SUPPORTED = List.of("bytea"); + + /** + * Create a new instance of the {@link com.exasol.adapter.dialects.snowflake.SnowflakeSqlGenerationVisitor}. + * + * @param dialect {@link SnowflakeSqlDialect} SQL dialect + * @param context SQL generation context + */ + public SnowflakeSqlGenerationVisitor(final SqlDialect dialect, final SqlGenerationContext context) { + super(dialect, context); + } + + protected List getListOfTypeNamesRequiringCast() { + return TYPE_NAMES_REQUIRING_CAST; + } + + protected List getListOfTypeNamesNotSupported() { + return TYPE_NAMES_NOT_SUPPORTED; + } + + @Override + protected String representAnyColumnInSelectList() { + return SqlConstants.ONE; + } + + @Override + public String visit(final SqlColumn column) throws AdapterException { + final String projectionString = super.visit(column); + return getColumnProjectionString(column, projectionString); + } + + private String getColumnProjectionString(final SqlColumn column, final String projectionString) + throws AdapterException { + return super.isDirectlyInSelectList(column) // + ? buildColumnProjectionString(getTypeNameFromColumn(column), projectionString) // + : projectionString; + } + + @Override + public String visit(final SqlFunctionScalar function) throws AdapterException { + final List arguments = function.getArguments(); + final List argumentsSql = new ArrayList<>(arguments.size()); + for (final SqlNode node : arguments) { + argumentsSql.add(node.accept(this)); + } + final ScalarFunction scalarFunction = function.getFunction(); + switch (scalarFunction) { + case ADD_DAYS: + return getAddDateTime(argumentsSql, "days"); + case ADD_HOURS: + return getAddDateTime(argumentsSql, "hours"); + case ADD_MINUTES: + return getAddDateTime(argumentsSql, "mins"); + case ADD_SECONDS: + return getAddDateTime(argumentsSql, "secs"); + case ADD_WEEKS: + return getAddDateTime(argumentsSql, "weeks"); + case ADD_YEARS: + return getAddDateTime(argumentsSql, "years"); + case ADD_MONTHS: + return getAddDateTime(argumentsSql, "months"); + case SECOND: + case MINUTE: + case DAY: + case WEEK: + case MONTH: + case YEAR: + return getDateTime(argumentsSql, scalarFunction); + case POSIX_TIME: + return getPosixTime(argumentsSql); + case FLOAT_DIV: + return getCastToDoublePrecisionAndDivide(argumentsSql); + default: + return super.visit(function); + } + } + + private String getCastToDoublePrecisionAndDivide(final List sqlArguments) { + return "( CAST (" + sqlArguments.get(0) + " AS DOUBLE PRECISION) / CAST (" + sqlArguments.get(1) + + " AS DOUBLE PRECISION))"; + } + + private String getAddDateTime(final List argumentsSql, final String unit) { + final StringBuilder builder = new StringBuilder(); + builder.append(argumentsSql.get(0)); + builder.append(" + "); + builder.append(buildInterval(argumentsSql, unit)); + return builder.toString(); + } + + private String buildInterval(final List argumentsSql, final String unit) { + return "make_interval(" + unit + " => " + argumentsSql.get(1) + ")"; + } + + private String getDateTime(final List argumentsSql, final ScalarFunction scalarFunction) { + final StringBuilder builder = new StringBuilder(); + builder.append("CAST(DATE_PART("); + appendDatePart(scalarFunction, builder); + builder.append(","); + builder.append(argumentsSql.get(0)); + builder.append(") AS DECIMAL("); + appendDecimalSize(scalarFunction, builder); + builder.append(",0))"); + return builder.toString(); + } + + private static void appendDatePart(ScalarFunction scalarFunction, StringBuilder builder) { + switch (scalarFunction) { + case SECOND: + builder.append("'SECOND'"); + break; + case MINUTE: + builder.append("'MINUTE'"); + break; + case DAY: + builder.append("'DAY'"); + break; + case WEEK: + builder.append("'WEEK'"); + break; + case MONTH: + builder.append("'MONTH'"); + break; + case YEAR: + builder.append("'YEAR'"); + break; + default: + break; + } + } + + private static void appendDecimalSize(ScalarFunction scalarFunction, StringBuilder builder) { + switch (scalarFunction) { + case SECOND: + case MINUTE: + case DAY: + case WEEK: + case MONTH: + builder.append("2"); + break; + case YEAR: + builder.append("4"); + break; + default: + break; + } + } + + private String getPosixTime(final List argumentsSql) { + return "EXTRACT(EPOCH FROM " + argumentsSql.get(0) + ")"; + } + + private String buildColumnProjectionString(final String typeName, final String projectionString) { + if (checkIfNeedToCastToVarchar(typeName)) { + return "CAST(" + projectionString + " as VARCHAR )"; + } else if (typeName.startsWith("smallserial")) { + return "CAST(" + projectionString + " as SMALLINT )"; + } else if (typeName.startsWith("serial")) { + return "CAST(" + projectionString + " as INTEGER )"; + } else if (typeName.startsWith("bigserial")) { + return "CAST(" + projectionString + " as BIGINT )"; + } else if (TYPE_NAMES_NOT_SUPPORTED.contains(typeName)) { + return "cast('" + typeName + " NOT SUPPORTED' as varchar) as not_supported"; + } else { + return projectionString; + } + } + + private boolean checkIfNeedToCastToVarchar(final String typeName) { + final List typesToVarcharCast = Arrays.asList("point", "line", "varbit", "lseg", "box", "path", + "polygon", "circle", "cidr", "citext", "inet", "macaddr", "interval", "json", "jsonb", "uuid", + "tsquery", "tsvector", "xml"); + return typesToVarcharCast.contains(typeName); + } + + @Override + public String visit(final SqlFunctionAggregateGroupConcat function) throws AdapterException { + final StringBuilder builder = new StringBuilder(); + builder.append("STRING_AGG"); + builder.append("("); + final String expression = function.getArgument().accept(this); + builder.append(expression); + builder.append(", "); + final String separator = function.hasSeparator() ? function.getSeparator().accept(this) : "','"; + builder.append(separator); + builder.append(") "); + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java new file mode 100644 index 0000000..d7124ac --- /dev/null +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java @@ -0,0 +1,31 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.adapter.AdapterProperties.IGNORE_ERRORS_PROPERTY; + +import java.sql.Connection; +import java.util.logging.Logger; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.IdentifierConverter; +import com.exasol.adapter.jdbc.*; +import com.exasol.errorreporting.ExaError; + +/** + * This class handles the specifics of mapping Snowflake table metadata to Exasol. + */ +public class SnowflakeTableMetadataReader extends BaseTableMetadataReader { + static final Logger LOGGER = Logger.getLogger(SnowflakeTableMetadataReader.class.getName()); + + /** + * Create a new {@link SnowflakeTableMetadataReader} instance. + * + * @param connection JDBC connection to the remote data source + * @param columnMetadataReader reader to be used to map the metadata of the tables columns + * @param properties user-defined adapter properties + * @param identifierConverter converter between source and Exasol identifiers + */ + public SnowflakeTableMetadataReader(final Connection connection, final ColumnMetadataReader columnMetadataReader, + final AdapterProperties properties, final IdentifierConverter identifierConverter) { + super(connection, columnMetadataReader, properties, identifierConverter); + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/services/com.exasol.adapter.dialects.SqlDialectFactory b/src/main/resources/META-INF/services/com.exasol.adapter.dialects.SqlDialectFactory new file mode 100644 index 0000000..0e0c9f8 --- /dev/null +++ b/src/main/resources/META-INF/services/com.exasol.adapter.dialects.SqlDialectFactory @@ -0,0 +1 @@ +com.exasol.adapter.dialects.snowflake.SnowflakeSqlDialectFactory \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/DialectTestData.java b/src/test/java/com/exasol/adapter/dialects/DialectTestData.java new file mode 100644 index 0000000..7202485 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/DialectTestData.java @@ -0,0 +1,69 @@ +package com.exasol.adapter.dialects; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import com.exasol.adapter.adapternotes.ColumnAdapterNotes; +import com.exasol.adapter.adapternotes.ColumnAdapterNotesJsonConverter; +import com.exasol.adapter.metadata.*; +import com.exasol.adapter.sql.*; + +public class DialectTestData { + + public static SqlNode getTestSqlNode() { + // SELECT USER_ID, count(URL) FROM CLICKS + // WHERE 1 < USER_ID + // GROUP BY USER_ID + // HAVING 1 < COUNT(URL) + // ORDER BY USER_ID + // LIMIT 10; + final TableMetadata clicksMeta = getClicksTableMetadata(); + final SqlTable fromClause = new SqlTable("CLICKS", clicksMeta); + final SqlSelectList selectList = SqlSelectList.createRegularSelectList( + List.of(new SqlColumn(0, clicksMeta.getColumns().get(0)), new SqlFunctionAggregate( + AggregateFunction.COUNT, List.of(new SqlColumn(1, clicksMeta.getColumns().get(1))), false))); + final SqlNode whereClause = new SqlPredicateLess(new SqlLiteralExactnumeric(BigDecimal.ONE), + new SqlColumn(0, clicksMeta.getColumns().get(0))); + final SqlExpressionList groupBy = new SqlGroupBy(List.of(new SqlColumn(0, clicksMeta.getColumns().get(0)))); + final SqlNode countUrl = new SqlFunctionAggregate(AggregateFunction.COUNT, + List.of(new SqlColumn(1, clicksMeta.getColumns().get(1))), false); + final SqlNode having = new SqlPredicateLess(new SqlLiteralExactnumeric(BigDecimal.ONE), countUrl); + final SqlOrderBy orderBy = new SqlOrderBy(List.of(new SqlColumn(0, clicksMeta.getColumns().get(0))), + List.of(true), List.of(true)); + final SqlLimit limit = new SqlLimit(10); + return SqlStatementSelect.builder().selectList(selectList).fromClause(fromClause).whereClause(whereClause) + .groupBy(groupBy).having(having).orderBy(orderBy).limit(limit).build(); + } + + public static TableMetadata getClicksTableMetadata() { + final ColumnAdapterNotesJsonConverter converter = ColumnAdapterNotesJsonConverter.getInstance(); + final List columns = new ArrayList<>(); + final ColumnAdapterNotes decimalAdapterNotes = ColumnAdapterNotes.builder() // + .jdbcDataType(3) // + .typeName("DECIMAL") // + .build(); + final ColumnAdapterNotes varcharAdapterNotes = ColumnAdapterNotes.builder() // + .jdbcDataType(12) // + .typeName("VARCHAR") // + .build(); + columns.add(ColumnMetadata.builder() // + .name("USER_ID") // + .adapterNotes(converter.convertToJson(decimalAdapterNotes)).type(DataType.createDecimal(18, 0)) // + .nullable(true) // + .identity(false) // + .defaultValue("") // + .comment("") // + .build()); + columns.add(ColumnMetadata.builder() // + .name("URL") // + .adapterNotes(converter.convertToJson(varcharAdapterNotes)) // + .type(DataType.createVarChar(10000, DataType.ExaCharset.UTF8)) // + .nullable(true) // + .identity(false) // + .defaultValue("") // + .comment("") // + .build()); + return new TableMetadata("CLICKS", "", columns, ""); + } +} \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java new file mode 100644 index 0000000..c758103 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java @@ -0,0 +1,58 @@ +package com.exasol.adapter.dialects.snowflake; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import java.sql.Types; +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.BaseIdentifierConverter; +import com.exasol.adapter.jdbc.JDBCTypeDescription; +import com.exasol.adapter.metadata.DataType; + +class SnowflakeColumnMetadataReaderTest { + private SnowflakeColumnMetadataReader columnMetadataReader; + private Map rawProperties; + + @BeforeEach + void beforeEach() { + this.columnMetadataReader = createDefaultSnowflakeColumnMetadataReader(); + this.rawProperties = new HashMap<>(); + } + + private SnowflakeColumnMetadataReader createDefaultSnowflakeColumnMetadataReader() { + return new SnowflakeColumnMetadataReader(null, AdapterProperties.emptyProperties(), + BaseIdentifierConverter.createDefault()); + } + + @Test + void testMapJdbcTypeOther() { + assertThat(mapJdbcType(Types.OTHER), equalTo(DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8))); + } + + protected DataType mapJdbcType(final int type) { + final JDBCTypeDescription jdbcTypeDescription = new JDBCTypeDescription(type, 0, 0, 0, ""); + return this.columnMetadataReader.mapJdbcType(jdbcTypeDescription); + } + + @ValueSource(ints = { Types.SQLXML, Types.DISTINCT }) + @ParameterizedTest + void testMapJdbcTypeFallbackToMaxVarChar(final int type) { + assertThat(mapJdbcType(type), equalTo(DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8))); + } + + @Test + void testMapJdbcTypeFallbackToParent() { + assertThat(mapJdbcType(Types.BOOLEAN), equalTo(DataType.createBool())); + } + + + +} diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReaderTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReaderTest.java new file mode 100644 index 0000000..f484566 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReaderTest.java @@ -0,0 +1,32 @@ +package com.exasol.adapter.dialects.snowflake; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.IdentifierCaseHandling; +import com.exasol.adapter.dialects.IdentifierConverter; + +class SnowflakeMetadataReaderTest { + private SnowflakeMetadataReader reader; + + @BeforeEach + void beforeEach() { + this.reader = new SnowflakeMetadataReader(null, AdapterProperties.emptyProperties()); + } + + @Test + void testGetTableMetadataReader() { + assertThat(this.reader.getTableMetadataReader(), instanceOf(SnowflakeTableMetadataReader.class)); + } + + @Test + void testGetColumnMetadataReader() { + assertThat(this.reader.getColumnMetadataReader(), instanceOf(SnowflakeColumnMetadataReader.class)); + } +} \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactoryTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactoryTest.java new file mode 100644 index 0000000..2acb0f0 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactoryTest.java @@ -0,0 +1,30 @@ +package com.exasol.adapter.dialects.snowflake; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import com.exasol.adapter.AdapterProperties; + +public class SnowflakeSqlDialectFactoryTest { + private SnowflakeSqlDialectFactory factory; + + @BeforeEach + void beforeEach() { + this.factory = new SnowflakeSqlDialectFactory(); + } + + @Test + void testGetName() { + assertThat(this.factory.getSqlDialectName(), equalTo("SNOWFLAKE")); + } + + @Test + void testCreateDialect() { + assertThat(this.factory.createSqlDialect(null, AdapterProperties.emptyProperties()), + instanceOf(SnowflakeSqlDialect.class)); + } +} \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java new file mode 100644 index 0000000..acf81fe --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -0,0 +1,609 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.matcher.ResultSetMatcher.matchesResultSet; +import static com.exasol.matcher.ResultSetStructureMatcher.table; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.sql.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Date; +import java.util.stream.Collectors; + +import org.hamcrest.MatcherAssert; +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; + +import com.exasol.closeafterall.CloseAfterAll; +import com.exasol.closeafterall.CloseAfterAllExtension; +import com.exasol.dbbuilder.dialects.DatabaseObjectException; +import com.exasol.dbbuilder.dialects.Schema; +import com.exasol.dbbuilder.dialects.exasol.VirtualSchema; +import com.exasol.matcher.TypeMatchMode; + +@Tag("integration") +@ExtendWith({ CloseAfterAllExtension.class }) +class SnowflakeSqlDialectIT { + @CloseAfterAll + private static final SnowflakeVirtualSchemaIntegrationTestSetup SETUP = new SnowflakeVirtualSchemaIntegrationTestSetup(); + private static final String SCHEMA_SNOWFLAKE = "SCHEMA_SNOWFLAKE"; + private static final String SCHEMA_SNOWFLAKE_UPPERCASE_TABLE = "schema_snowflake_upper"; + private static final String TABLE_SNOWFLAKE_SIMPLE = "table_snowflake_simple"; + private static final String TABLE_SNOWFLAKE_MIXED_CASE = "Table_Snowflake_Mixed_Case"; + private static final String TABLE_SNOWFLAKE_LOWER_CASE = "table_snowflake_lower_case"; + private static final String TABLE_SNOWFLAKE_ALL_DATA_TYPES = "table_snowflake_all_data_types"; + private static Schema exasolSchema; + private static VirtualSchema virtualSchemaSnowflake; + private static VirtualSchema virtualSchemaSnowflakeUppercaseTable; + private static final String TABLE_JOIN_1 = "TABLE_JOIN_1"; + private static final String TABLE_JOIN_2 = "TABLE_JOIN_2"; + private static VirtualSchema virtualSchemaSnowflakePreserveOriginalCase; + private static String QUALIFIED_TABLE_JOIN_NAME_1; + private static String QUALIFIED_TABLE_JOIN_NAME_2; + private static Statement statementExasol; + + @BeforeAll + static void beforeAll() throws SQLException { + final Statement statementSnowflake = SETUP.getSnowflakeStatement(); + statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE + " CASCADE"); + statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + " CASCADE"); + statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE); + statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE); + createSnowflakeTestTableSimple(statementSnowflake); + // createSnowflakeTestTableAllDataTypes(statementSnowflake); + // createSnowflakeTestTableMixedCase(statementSnowflake); + // createSnowflakeTestTableLowerCase(statementSnowflake); + // createTestTablesForJoinTests(SCHEMA_SNOWFLAKE); + statementExasol = SETUP.getExasolStatement(); + virtualSchemaSnowflake = SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE, Map.of()); + // virtualSchemaSnowflakeUppercaseTable = SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE_UPPERCASE_TABLE, + // Map.of("IGNORE_ERRORS", "SNOWFLAKE_UPPERCASE_TABLES")); + // virtualSchemaSnowflakePreserveOriginalCase = SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE_UPPERCASE_TABLE, + // Map.of("SNOWFLAKE_IDENTIFIER_MAPPING", "PRESERVE_ORIGINAL_CASE")); + // QUALIFIED_TABLE_JOIN_NAME_1 = virtualSchemaSnowflake.getName() + "." + TABLE_JOIN_1; + // QUALIFIED_TABLE_JOIN_NAME_2 = virtualSchemaSnowflake.getName() + "." + TABLE_JOIN_2; + exasolSchema = SETUP.getExasolFactory().createSchema("EXASOL_TEST_SCHEMA"); + } + + private static void createSnowflakeTestTableSimple(final Statement statementSnowflake) throws SQLException { + final String qualifiedTableName = SCHEMA_SNOWFLAKE + "." + TABLE_SNOWFLAKE_SIMPLE; + statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (x NUMBER(36,0))"); + statementSnowflake.execute("INSERT INTO " + qualifiedTableName + " VALUES (1)"); + } + + private static void createSnowflakeTestTableAllDataTypes(final Statement statementSnowflake) throws SQLException { + final String qualifiedTableName = SCHEMA_SNOWFLAKE + "." + TABLE_SNOWFLAKE_ALL_DATA_TYPES; + statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (" // + + "myBigint BIGINT, " // + + "myBigserial BIGSERIAL, " // + + "myBit BIT, " // + + "myBitVar BIT, " // + + "myBoolean BOOLEAN, " // + + "myBox BOX, " // + + "myBytea BYTEA, " // + + "myCharacter CHARACTER(1000), " // + + "myCharacterVar CHARACTER, " // + + "myCidr CIDR, " // + + "myCircle CIRCLE, " // + + "myDate DATE, " // + + "myDouble DOUBLE PRECISION, " // + + "myInet INET, " // + + "myInteger INTEGER, " // + + "myInterval INTERVAL, " // + + "myJson JSON, " // + + "myJsonB JSONB, " // + + "myLine LINE, " // + + "myLseg LSEG, " // + + "myMacAddr MACADDR, " // + + "myMoney MONEY, " // + + "myNumeric NUMERIC(36, 10), " // + + "myPath PATH, " // + + "myPoint POINT, " // + + "myPolygon POLYGON, " // + + "myReal REAL, " // + + "mySmallint SMALLINT, " // + + "myText TEXT, " // + + "myTime TIME, " // + + "myTimeWithTimeZone TIME WITH TIME ZONE, " // + + "myTimestamp TIMESTAMP, " // + + "myTimestampWithTimeZone TIMESTAMP WITH TIME ZONE, " // + + "myTsquery TSQUERY, " // + + "myTsvector TSVECTOR, " // + + "myUuid UUID, " // + + "myXml XML " // + + ")"); + statementSnowflake.execute("INSERT INTO " + qualifiedTableName + " VALUES (" // + + "10000000000, " // myBigint + + "nextval('" + qualifiedTableName + "_myBigserial_seq'::regclass), " // myBigserial + + "B'1', " // myBit + + "B'0', " // myBitVar + + "false, " // myBoolean + + "'( ( 1 , 8 ) , ( 4 , 16 ) )', " // myBox + + "E'\\\\000'::bytea, " // myBytea + + "'hajksdf', " // myCharacter + + "'hjkdhjgfh', " // myCharacterVar + + "'192.168.100.128/25'::cidr, " // myCidr + + "'( ( 1 , 5 ) , 3 )'::circle, " // myCircle + + "'2010-01-01', " // myDate + + "192189234.1723854, " // myDouble + + "'192.168.100.128'::inet, " // myInet + + "7189234, " // myInteger + + "INTERVAL '1' YEAR, " // myInterval + + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::json, " // myJson + + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::jsonb, " // myJsonB + + "'{ 1, 2, 3 }'::line, " // myLine + + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::lseg, " // myLseg + + "'08:00:2b:01:02:03'::macaddr, " // myMacAddr + + "100.01, " // myMoney + + "24.23, " // myNumeric + + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::path, " // myPath + + "'( 1 , 3 )'::point, " // myPoint + + "'( ( 1 , 2 ) , (2,4),(3,7) )'::polygon, " // myPolygon + + "10.12, " // myReal + + "100, " // mySmallint + + "'This cat is super cute', " // myText + + "'11:11:11', " // myTime + + "'11:11:11 +01:00', " // myTimeWithTimeZone + + "'2010-01-01 11:11:11', " // myTimestamp + + "'2010-01-01 11:11:11 +01:00', " // myTimestampwithtimezone + + "'fat & rat'::tsquery, " // myTsquery + + "to_tsvector('english', 'The Fat Rats'), " // myTsvector + + "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, " // myUuid + + "XMLPARSE (DOCUMENT 'Manual...') " // myXml + + ")"); + } + + private static void createSnowflakeTestTableMixedCase(final Statement statementSnowflake) throws SQLException { + final String qualifiedTableName = SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + ".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\""; + statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (x INT, \"Y\" INT)"); + } + + private static void createSnowflakeTestTableLowerCase(final Statement statementSnowflake) throws SQLException { + final String qualifiedTableName = SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + "." + TABLE_SNOWFLAKE_LOWER_CASE; + statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (x INT, y INT)"); + } + + private static void createTestTablesForJoinTests(final String schemaName) throws SQLException { + final Statement statement = SETUP.getSnowflakeStatement(); + statement.execute("CREATE TABLE " + schemaName + "." + TABLE_JOIN_1 + "(x INT, y VARCHAR(100))"); + statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_1 + " VALUES (1,'aaa')"); + statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_1 + " VALUES (2,'bbb')"); + statement.execute("CREATE TABLE " + schemaName + "." + TABLE_JOIN_2 + "(x INT, y VARCHAR(100))"); + statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_2 + " VALUES (2,'bbb')"); + statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_2 + " VALUES (3,'ccc')"); + } + + @Test + void testSelectSingleColumn() throws SQLException { + final ResultSet actualResultSet = statementExasol + .executeQuery("SELECT * FROM " + virtualSchemaSnowflake.getName() + "." + TABLE_SNOWFLAKE_SIMPLE); + assertThat(actualResultSet, table().row(1).matches(TypeMatchMode.NO_JAVA_TYPE_CHECK)); + } + + @Test + void testInnerJoin() throws SQLException { + final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a INNER JOIN " + + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x"; + final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + List.of("2,'bbb', 2,'bbb'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testInnerJoinWithProjection() throws SQLException { + final String query = "SELECT b.y || " + QUALIFIED_TABLE_JOIN_NAME_1 + ".y FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + + " INNER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON " + QUALIFIED_TABLE_JOIN_NAME_1 + ".x=b.x"; + final ResultSet expected = getExpectedResultSet(List.of("y VARCHAR(100)"), // + List.of("'bbbbbb'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testLeftJoin() throws SQLException { + final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a LEFT OUTER JOIN " + + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x ORDER BY a.x"; + final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + List.of("1, 'aaa', null, null", // + "2, 'bbb', 2, 'bbb'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testRightJoin() throws SQLException { + final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a RIGHT OUTER JOIN " + + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x ORDER BY a.x"; + final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + List.of("2, 'bbb', 2, 'bbb'", // + "null, null, 3, 'ccc'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testFullOuterJoin() throws SQLException { + final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a FULL OUTER JOIN " + + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x ORDER BY a.x"; + final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + List.of("1, 'aaa', null, null", // + "2, 'bbb', 2, 'bbb'", // + "null, null, 3, 'ccc'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testRightJoinWithComplexCondition() throws SQLException { + final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a RIGHT OUTER JOIN " + + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x||a.y=b.x||b.y ORDER BY a.x"; + final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + List.of("2, 'bbb', 2, 'bbb'", // + "null, null, 3, 'ccc'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testFullOuterJoinWithComplexCondition() throws SQLException { + final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a FULL OUTER JOIN " + + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x-b.x=0 ORDER BY a.x"; + final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + List.of("1, 'aaa', null, null", // + "2, 'bbb', 2, 'bbb'", // + "null, null, 3, 'ccc'")); + assertThat(getActualResultSet(query), matchesResultSet(expected)); + } + + @Test + void testYearScalarFunctionFromTimeStamp() throws SQLException { + final String query = "SELECT year(\"MYTIMESTAMP\") FROM " + virtualSchemaSnowflake.getName() + "." + + TABLE_SNOWFLAKE_ALL_DATA_TYPES; + final ResultSet actualResultSet = getActualResultSet(query); + final Short yearShort = 2010; + assertThat(actualResultSet, table().row(yearShort).matches()); + } + + @Test + void testYearScalarFunctionFromDate() throws SQLException { + final String query = "SELECT year(\"MYDATE\") FROM " + virtualSchemaSnowflake.getName() + "." + + TABLE_SNOWFLAKE_ALL_DATA_TYPES; + final ResultSet actualResultSet = getActualResultSet(query); + final Short yearShort = 2010; + assertThat(actualResultSet, table().row(yearShort).matches()); + } + + // Check 'current_schema' functionality, re-enable tests after resolution + // currently a bug in the compiler, compiler always expects 'VARCHAR(1) ASCII' see + // https://github.com/exasol/snowflake-virtual-schema/issues/79 + // https://exasol.atlassian.net/browse/SPOT-19716 + @Disabled("Currently a bug in the compiler, compiler always expects 'VARCHAR(1) ASCII'") + @Test + void testCurrentSchemaScalarFunction() throws SQLException { + final String query = " SELECT current_schema FROM " + virtualSchemaSnowflake.getName() + "." + + TABLE_SNOWFLAKE_ALL_DATA_TYPES; + final ResultSet actualResultSet = getActualResultSet(query); + assertThat(actualResultSet, table().row(TABLE_SNOWFLAKE_ALL_DATA_TYPES).matches()); + } + + @Test + void testFloatDivFunction() throws SQLException { + final String query = " SELECT MYINTEGER / MYINTEGER FROM " + virtualSchemaSnowflake.getName() + "." + + TABLE_SNOWFLAKE_ALL_DATA_TYPES; + final ResultSet actualResultSet = getActualResultSet(query); + assertThat(actualResultSet, table("DOUBLE PRECISION").row(1.0).matches()); + } + + @Test + void testCountAll() throws SQLException { + final String qualifiedExpectedTableName = virtualSchemaSnowflake.getName() + "." + TABLE_SNOWFLAKE_SIMPLE; + final String query = "SELECT COUNT(*) FROM " + qualifiedExpectedTableName; + final ResultSet actualResultSet = getActualResultSet(query); + assertThat(actualResultSet, table("BIGINT").row(1L).matches()); + } + + @Test + void testCreateSchemaWithUpperCaseTablesThrowsException() { + final Exception exception = assertThrows(DatabaseObjectException.class, + () -> SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE_UPPERCASE_TABLE, Map.of())); + assertThat(exception.getMessage(), containsString("Failed to write to object")); + } + + @Test + void testQueryUpperCaseTableQuotedThrowsException() { + final String selectStatement = "SELECT x FROM " + virtualSchemaSnowflakeUppercaseTable.getName() + ".\"" + + TABLE_SNOWFLAKE_MIXED_CASE + "\""; + final Exception exception = assertThrows(SQLException.class, () -> statementExasol.execute(selectStatement)); + assertThat(exception.getMessage(), containsString(".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\" not found")); + } + + @Test + void testQueryUpperCaseTableThrowsException() { + final Exception exception = assertThrows(SQLException.class, () -> statementExasol.execute( + "SELECT x FROM " + virtualSchemaSnowflakeUppercaseTable.getName() + "." + TABLE_SNOWFLAKE_MIXED_CASE)); + assertThat(exception.getMessage(), containsString("object " + virtualSchemaSnowflakeUppercaseTable.getName() + + "." + TABLE_SNOWFLAKE_MIXED_CASE.toUpperCase() + " not found")); + } + + @Test + void testQueryLowerCaseTable() throws SQLException { + final ResultSet result = statementExasol.executeQuery( + "SELECT x FROM " + virtualSchemaSnowflakeUppercaseTable.getName() + "." + TABLE_SNOWFLAKE_LOWER_CASE); + assertThat(result.next(), equalTo(false)); + } + + @Test + void testUnsetIgnoreUpperCaseTablesAndRefreshThrowsException() throws SQLException { + statementExasol.execute( + "ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + " set ignore_errors=''"); + statementExasol.execute("ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + + " set SNOWFLAKE_IDENTIFIER_MAPPING = 'CONVERT_TO_UPPER'"); + final Exception exception = assertThrows(SQLException.class, () -> statementExasol + .execute("ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + " REFRESH")); + assertThat(exception.getMessage(), containsString("E-VSSF-6: Table '" + TABLE_SNOWFLAKE_MIXED_CASE + + "' cannot be used in virtual schema. Set property 'IGNORE_ERRORS' to 'SNOWFLAKE_UPPERCASE_TABLES' to enforce schema creation.")); + } + + @Test + void testSetIgnoreUpperCaseTablesAndRefresh() throws SQLException { + statementExasol.execute("ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + + " set ignore_errors='SNOWFLAKE_UPPERCASE_TABLES'"); + final String refresh_schema_query = "ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + + " REFRESH"; + assertDoesNotThrow(() -> statementExasol.execute(refresh_schema_query)); + } + + @Test + void testPreserveCaseQueryLowerCaseTableThrowsException() { + final SQLException exception = assertThrows(SQLException.class, + () -> statementExasol.executeQuery("SELECT x FROM " + + virtualSchemaSnowflakePreserveOriginalCase.getName() + "." + TABLE_SNOWFLAKE_LOWER_CASE)); + assertThat(exception.getMessage(), + containsString("object " + virtualSchemaSnowflakePreserveOriginalCase.getName() + "." + + TABLE_SNOWFLAKE_LOWER_CASE.toUpperCase() + " not found")); + } + + @Test + void testPreserveCaseQueryLowerCaseTableWithQuotes() throws SQLException { + final ResultSet result = statementExasol.executeQuery("SELECT \"x\" FROM " + + virtualSchemaSnowflakePreserveOriginalCase.getName() + ".\"" + TABLE_SNOWFLAKE_LOWER_CASE + "\""); + assertThat(result.next(), equalTo(false)); + } + + @Test + void testPreserveCaseQueryUpperCaseTableWithQuotes() throws SQLException { + final ResultSet result = statementExasol.executeQuery("SELECT \"Y\" FROM " + + virtualSchemaSnowflakePreserveOriginalCase.getName() + ".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\""); + assertThat(result.next(), equalTo(false)); + } + + @Test + void testDatatypeBigint() throws SQLException { + assertSingleValue("myBigint", "DECIMAL(19,0)", "10000000000"); + } + + @Test + void testPreserveCaseQueryUpperCaseTableWithQuotesLowerCaseColumn() throws SQLException { + final ResultSet result = statementExasol.executeQuery("SELECT \"x\" FROM " + + virtualSchemaSnowflakePreserveOriginalCase.getName() + ".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\""); + assertThat(result.next(), equalTo(false)); + } + + @Test + void testDatatypeBigSerial() throws SQLException { + assertSingleValue("myBigserial", "DECIMAL(19,0)", "1"); + } + + @Test + void testDatatypeBit() throws SQLException { + assertSingleValue("myBit", "BOOLEAN", true); + } + + @Test + void testDatatypeBitVar() throws SQLException { + assertSingleValue("myBitvar", "VARCHAR(5) UTF8", "0"); + } + + @Test + void testDatatypeBoolean() throws SQLException { + assertSingleValue("myBoolean", "BOOLEAN", false); + } + + @Test + void testDatatypeBox() throws SQLException { + assertSingleValue("myBox", "VARCHAR(2000000) UTF8", "(4,16),(1,8)"); + } + + @Test + void testDatatypeBytea() throws SQLException { + assertSingleValue("myBytea", "VARCHAR(2000000) UTF8", "bytea NOT SUPPORTED"); + } + + @Test + void testDatatypeCharacter() throws SQLException { + final String empty = " "; + final String expected = "hajksdf" + String.join("", Collections.nCopies(993, empty)); + assertSingleValue("myCharacter", "CHAR(1000) UTF8", expected); + } + + @Test + void testDatatypeCharacterVar() throws SQLException { + assertSingleValue("myCharactervar", "VARCHAR(1000) UTF8", "hjkdhjgfh"); + } + + @Test + void testDatatypeCidr() throws SQLException { + assertSingleValue("myCidr", "VARCHAR(2000000) UTF8", "192.168.100.128/25"); + } + + @Test + void testDatatypeCircle() throws SQLException { + assertSingleValue("myCircle", "VARCHAR(2000000) UTF8", "<(1,5),3>"); + } + + @Test + void testDatatypeDate() throws SQLException, ParseException { + final Date expectedDate = new SimpleDateFormat("yyyy-MM-dd").parse("2010-01-01"); + assertSingleValue("myDate", "DATE", expectedDate); + } + + @Test + void testDatatypeDouble() throws SQLException { + assertSingleValue("myDouble", "DOUBLE", "192189234.1723854"); + } + + @Test + void testDatatypeInet() throws SQLException { + assertSingleValue("myInet", "VARCHAR(2000000) UTF8", "192.168.100.128/32"); + } + + @Test + void testDatatypeInteger() throws SQLException { + assertSingleValue("myInteger", "DECIMAL(10,0)", "7189234"); + } + + @Test + void testDatatypeIntervalYM() throws SQLException { + assertSingleValue("myInterval", "VARCHAR(2000000) UTF8", "1 year"); + } + + @Test + void testDatatypeJSON() throws SQLException { + assertSingleValue("myJson", "VARCHAR(2000000) UTF8", + "{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}"); + } + + @Test + void testDatatypeJSONB() throws SQLException { + assertSingleValue("myJsonb", "VARCHAR(2000000) UTF8", + "{\"bar\": \"baz\", \"active\": false, \"balance\": 7.77}"); + } + + @Test + void testDatatypeLine() throws SQLException { + assertSingleValue("myLine", "VARCHAR(2000000) UTF8", "{1,2,3}"); + } + + @Test + void testDatatypeLSeg() throws SQLException { + assertSingleValue("myLseg", "VARCHAR(2000000) UTF8", "[(1,2),(3,4)]"); + } + + @Test + void testDatatypeMACAddr() throws SQLException { + assertSingleValue("myMacaddr", "VARCHAR(2000000) UTF8", "08:00:2b:01:02:03"); + } + + @Test + void testDatatypeMoney() throws SQLException { + assertSingleValue("myMoney", "DOUBLE", 100.01); + } + + @Test + void testDatatypeNumeric() throws SQLException { + assertSingleValue("myNumeric", "VARCHAR(2000000) UTF8", 24.2300000000); + } + + @Test + void testDatatypePath() throws SQLException { + assertSingleValue("myPath", "VARCHAR(2000000) UTF8", "[(1,2),(3,4)]"); + } + + @Test + void testDatatypePoint() throws SQLException { + assertSingleValue("myPoint", "VARCHAR(2000000) UTF8", "(1,3)"); + } + + @Test + void testDatatypePolygon() throws SQLException { + assertSingleValue("myPolygon", "VARCHAR(2000000) UTF8", "((1,2),(2,4),(3,7))"); + } + + @Test + void testDatatypeReal() throws SQLException { + assertSingleValue("myReal", "DOUBLE", 10.12); + } + + @Test + void testDatatypeSmallInt() throws SQLException { + assertSingleValue("mySmallint", "DECIMAL(5,0)", 100); + } + + @Test + void testDatatypeText() throws SQLException { + assertSingleValue("myText", "VARCHAR(2000000) UTF8", "This cat is super cute"); + } + + @Test + void testDatatypeTime() throws SQLException { + assertSingleValue("myTime", "VARCHAR(2000000) UTF8", "1970-01-01 11:11:11.0"); + } + + @Test + void testDatatypeTimeWithTimezone() throws SQLException { + assertSingleValue("myTimeWithTimeZone", "VARCHAR(2000000) UTF8", "1970-01-01 11:11:11.0"); + } + + @Test + void testDatatypeTimestamp() throws SQLException, ParseException { + final Timestamp expectedDate = new Timestamp( + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2010-01-01 11:11:11").getTime()); + assertSingleValue("myTimestamp", "TIMESTAMP", expectedDate); + } + + @Test + void testDatatypeTimestampWithTimezone() throws SQLException, ParseException { + final Timestamp expectedDate = new Timestamp( + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2010-01-01 11:11:11").getTime()); + assertSingleValue("myTimestampwithtimezone", "TIMESTAMP", expectedDate); + } + + @Test + void testDatatypeTsQuery() throws SQLException { + assertSingleValue("myTsquery", "VARCHAR(2000000) UTF8", "'fat' & 'rat'"); + } + + @Test + void testDatatypeTsvector() throws SQLException { + assertSingleValue("myTsvector", "VARCHAR(2000000) UTF8", "'fat':2 'rat':3"); + } + + @Test + void testDatatypeUUID() throws SQLException { + assertSingleValue("myUuid", "VARCHAR(2000000) UTF8", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"); + } + + @Test + void testDatatypeXML() throws SQLException { + assertSingleValue("myXml", "VARCHAR(2000000) UTF8", + "Manual..."); + } + + private void assertSingleValue(final String columnName, final String expectedColumnType, final Object expectedValue) + throws SQLException { + final ResultSet actual = statementExasol.executeQuery("SELECT " + columnName + " FROM " + + virtualSchemaSnowflake.getName() + "." + TABLE_SNOWFLAKE_ALL_DATA_TYPES); + MatcherAssert.assertThat(actual, table().row(expectedValue).matches(TypeMatchMode.NO_JAVA_TYPE_CHECK)); + } + + // TODO refactor to use table().row().matches() + private ResultSet getExpectedResultSet(final List expectedColumns, final List expectedRows) + throws SQLException { + final String expectedValues = expectedRows.stream().map(row -> "(" + row + ")") + .collect(Collectors.joining(",")); + final String qualifiedExpectedTableName = exasolSchema.getName() + ".EXPECTED"; + final String createTableStatement = "CREATE OR REPLACE TABLE " + qualifiedExpectedTableName + "(" + + String.join(", ", expectedColumns) + ");"; + statementExasol.execute(createTableStatement); + final String insertIntoTableStatement = "INSERT INTO " + qualifiedExpectedTableName + " VALUES " + + expectedValues + ";"; + statementExasol.execute(insertIntoTableStatement); + final String selectStatement = "SELECT * FROM " + qualifiedExpectedTableName + ";"; + return statementExasol.executeQuery(selectStatement); + } + + private ResultSet getActualResultSet(final String query) throws SQLException { + return statementExasol.executeQuery(query); + } + +} diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java new file mode 100644 index 0000000..eafa795 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java @@ -0,0 +1,136 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.adapter.AdapterProperties.*; +import static com.exasol.adapter.capabilities.AggregateFunctionCapability.*; +import static com.exasol.adapter.capabilities.LiteralCapability.*; +import static com.exasol.adapter.capabilities.MainCapability.*; +import static com.exasol.adapter.capabilities.PredicateCapability.*; +import static com.exasol.adapter.dialects.snowflake.SnowflakeSqlDialect.DATABASE_NAME_PROPERTY; +import static com.exasol.adapter.dialects.snowflake.SnowflakeSqlDialect.ACCOUNT_NAME_PROPERTY; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; + +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.capabilities.Capabilities; +import com.exasol.adapter.dialects.SqlDialect; +import com.exasol.adapter.dialects.rewriting.ImportIntoTemporaryTableQueryRewriter; +import com.exasol.adapter.jdbc.ConnectionFactory; +import com.exasol.adapter.jdbc.RemoteMetadataReaderException; +import com.exasol.adapter.properties.PropertyValidationException; + +@ExtendWith(MockitoExtension.class) +class SnowflakeSqlDialectTest { + private SnowflakeSqlDialect dialect; + @Mock + private ConnectionFactory connectionFactoryMock; + + @BeforeEach + void beforeEach() { + this.dialect = new SnowflakeSqlDialect(this.connectionFactoryMock, AdapterProperties.emptyProperties()); + } + + @Test + void testCreateRemoteMetadataReader() { + assertThat(this.dialect.createRemoteMetadataReader(), instanceOf(SnowflakeMetadataReader.class)); + } + + @Test + void testCreateRemoteMetadataReaderConnectionFails(@Mock final Connection connectionMock) throws SQLException { + when(this.connectionFactoryMock.getConnection()).thenThrow(new SQLException()); + final RemoteMetadataReaderException exception = assertThrows(RemoteMetadataReaderException.class, + this.dialect::createRemoteMetadataReader); + assertThat(exception.getMessage(), containsString("E-VSSF-3")); + } + + @Test + void testCreateQueryRewriter() { + assertThat(this.dialect.createQueryRewriter(), instanceOf(ImportIntoTemporaryTableQueryRewriter.class)); + } + + @Test + void testGetCapabilities() { + final Capabilities capabilities = this.dialect.getCapabilities(); + assertAll( + () -> assertThat(capabilities.getMainCapabilities(), + containsInAnyOrder(SELECTLIST_PROJECTION, SELECTLIST_EXPRESSIONS, FILTER_EXPRESSIONS, + AGGREGATE_SINGLE_GROUP, AGGREGATE_GROUP_BY_COLUMN, AGGREGATE_GROUP_BY_EXPRESSION, + AGGREGATE_GROUP_BY_TUPLE, AGGREGATE_HAVING, ORDER_BY_COLUMN, ORDER_BY_EXPRESSION, LIMIT, + LIMIT_WITH_OFFSET, JOIN, JOIN_TYPE_INNER, JOIN_TYPE_LEFT_OUTER, JOIN_TYPE_RIGHT_OUTER, + JOIN_TYPE_FULL_OUTER, JOIN_CONDITION_EQUI)), + () -> assertThat(capabilities.getLiteralCapabilities(), + containsInAnyOrder(BOOL, NULL, DATE, TIMESTAMP, TIMESTAMP_UTC, DOUBLE, EXACTNUMERIC, STRING)), + () -> assertThat(capabilities.getPredicateCapabilities(), + containsInAnyOrder(AND, OR, NOT, EQUAL, NOTEQUAL, LESS, LESSEQUAL, LIKE, LIKE_ESCAPE, BETWEEN, + REGEXP_LIKE, IN_CONSTLIST, IS_NULL, IS_NOT_NULL)), + () -> assertThat(capabilities.getAggregateFunctionCapabilities(), + containsInAnyOrder(COUNT, COUNT_STAR, COUNT_DISTINCT, SUM, SUM_DISTINCT, MIN, MAX, AVG, + AVG_DISTINCT, MEDIAN, FIRST_VALUE, LAST_VALUE, STDDEV, STDDEV_DISTINCT, STDDEV_POP, + STDDEV_POP_DISTINCT, STDDEV_SAMP, STDDEV_SAMP_DISTINCT, VARIANCE, VARIANCE_DISTINCT, + VAR_POP, VAR_POP_DISTINCT, VAR_SAMP, VAR_SAMP_DISTINCT, GROUP_CONCAT)) // + ); + } +/* + @CsvSource({ "ABC, \"abc\"", // + "AbCde, \"abcde\"", // + "\"tableName, \"\"\"tablename\"" // + }) + @ParameterizedTest + void testApplyQuote(final String unquoted, final String quoted) { + assertThat(this.dialect.applyQuote(unquoted), equalTo(quoted)); + }*/ + + @ValueSource(strings = { "ab:E'ab'", "a'b:E'a''b'", "a''b:E'a''''b'", "'ab':E'''ab'''", "a\\\\b:E'a\\\\\\\\b'", + "a\\'b:E'a\\\\''b'" }) + @ParameterizedTest + void testGetLiteralString(final String definition) { + assertThat(this.dialect.getStringLiteral(definition.substring(0, definition.indexOf(':'))), + equalTo(definition.substring(definition.indexOf(':') + 1))); + } + + @Test + void testGetLiteralStringNull() { + assertThat(this.dialect.getStringLiteral(null), CoreMatchers.equalTo("NULL")); + } + + + @Test + void testValidateDatabaseProperty() throws PropertyValidationException { + final SqlDialect sqlDialect = new SnowflakeSqlDialect(null, new AdapterProperties(Map.of( // + CONNECTION_NAME_PROPERTY, "MY_CONN", // + CATALOG_NAME_PROPERTY, "TESTDB"))); + sqlDialect.validateProperties(); + } + + @Test + void testValidateAccountProperty() throws PropertyValidationException { + final SqlDialect sqlDialect = new SnowflakeSqlDialect(null, new AdapterProperties(Map.of( // + CONNECTION_NAME_PROPERTY, "MY_CONN", // + ACCOUNT_NAME_PROPERTY, "TESTDB"))); + sqlDialect.validateProperties(); + } + + @Test + void testValidateSchemaProperty() throws PropertyValidationException { + final SqlDialect sqlDialect = new SnowflakeSqlDialect(null, new AdapterProperties(Map.of( // + CONNECTION_NAME_PROPERTY, "MY_CONN", // + SCHEMA_NAME_PROPERTY, "MY_SCHEMA"))); + sqlDialect.validateProperties(); + } +} \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java new file mode 100644 index 0000000..a843d5b --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java @@ -0,0 +1,119 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.adapter.dialects.VisitorAssertions.assertSqlNodeConvertedToOne; +import static com.exasol.adapter.sql.ScalarFunction.POSIX_TIME; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.exasol.adapter.AdapterException; +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.DialectTestData; +import com.exasol.adapter.dialects.SqlDialect; +import com.exasol.adapter.dialects.rewriting.SqlGenerationContext; +import com.exasol.adapter.jdbc.ConnectionFactory; +import com.exasol.adapter.metadata.ColumnMetadata; +import com.exasol.adapter.metadata.DataType; +import com.exasol.adapter.sql.*; + +@ExtendWith(MockitoExtension.class) +class SnowflakeSqlGenerationVisitorTest { + private SnowflakeSqlGenerationVisitor visitor; + + @BeforeEach + void beforeEach(@Mock final ConnectionFactory connectionFactoryMock) { + final SqlDialect dialect = new SnowflakeSqlDialect(connectionFactoryMock, AdapterProperties.emptyProperties()); + final SqlGenerationContext context = new SqlGenerationContext("test_catalog", "test_schema", false); + this.visitor = new SnowflakeSqlGenerationVisitor(dialect, context); + } + + @CsvSource({ "ADD_DAYS, days", // + "ADD_HOURS, hours", // + "ADD_MINUTES, mins", // + "ADD_SECONDS, secs", // + "ADD_YEARS, years", // + "ADD_WEEKS, weeks", // + "ADD_MONTHS, months" }) + @ParameterizedTest + void testVisitSqlFunctionScalarAddDate(final ScalarFunction scalarFunction, final String expected) + throws AdapterException { + final SqlFunctionScalar sqlFunctionScalar = createSqlFunctionScalarForDateTest(scalarFunction, 10); + assertThat(this.visitor.visit(sqlFunctionScalar), + equalTo("\"test_column\" + make_interval(" + expected + " => 10)")); + } + + private SqlFunctionScalar createSqlFunctionScalarForDateTest(final ScalarFunction scalarFunction, + final int numericValue) { + final List arguments = new ArrayList<>(); + arguments.add(new SqlColumn(1, + ColumnMetadata.builder().name("test_column") + .adapterNotes("{\"jdbcDataType\":93, " + "\"typeName\":\"TIMESTAMP\"}") + .type(DataType.createChar(20, DataType.ExaCharset.UTF8)).build())); + arguments.add(new SqlLiteralExactnumeric(new BigDecimal(numericValue))); + return new SqlFunctionScalar(scalarFunction, arguments); + } + + @CsvSource({ "SECOND, SECOND, 2", // + "MINUTE, MINUTE, 2", // + "DAY, DAY, 2", // + "WEEK, WEEK, 2", // + "MONTH, MONTH, 2", // + "YEAR, YEAR, 4" }) + @ParameterizedTest + void testVisitSqlFunctionScalarDatetime(final ScalarFunction scalarFunction, final String expected, + final String decimalSize) throws AdapterException { + final SqlFunctionScalar sqlFunctionScalar = createSqlFunctionScalarForDateTest(scalarFunction, 0); + assertThat(this.visitor.visit(sqlFunctionScalar), + equalTo("CAST(DATE_PART('" + expected + "',\"test_column\") AS DECIMAL(" + decimalSize + ",0))")); + } + + @Test + void testVisitSqlFunctionScalarPosixTime() throws AdapterException { + final SqlFunctionScalar sqlFunctionScalar = createSqlFunctionScalarForDateTest(POSIX_TIME, 0); + assertThat(this.visitor.visit(sqlFunctionScalar), equalTo("EXTRACT(EPOCH FROM \"test_column\")")); + } + + @Test + void testVisitSqlSelectListAnyValue() throws AdapterException { + final SqlSelectList sqlSelectList = SqlSelectList.createAnyValueSelectList(); + assertSqlNodeConvertedToOne(sqlSelectList, this.visitor); + } + +/* @Test + void testVisitSqlStatementSelect() throws AdapterException { + final SqlStatementSelect select = (SqlStatementSelect) DialectTestData.getTestSqlNode(); + assertThat(this.visitor.visit(select), // + equalTo("SELECT \"user_id\", " // + + "COUNT(\"url\") FROM \"test_schema\".\"clicks\" " // + + "WHERE 1 < \"user_id\" " // + + "GROUP BY \"user_id\" " // + + "HAVING 1 < COUNT(\"url\") " // + + "ORDER BY \"user_id\" LIMIT 10")); + }*/ + + @Test + void testVisitSqlFunctionAggregateGroupConcat() throws AdapterException { + final SqlLiteralString argument = new SqlLiteralString("test"); + final ColumnMetadata columnMetadata = ColumnMetadata.builder().name("test_column").type(DataType.createBool()) + .build(); + final ColumnMetadata columnMetadata2 = ColumnMetadata.builder().name("test_column2") + .type(DataType.createDouble()).build(); + final List orderByArguments = List.of(new SqlColumn(1, columnMetadata), + new SqlColumn(2, columnMetadata2)); + final SqlOrderBy orderBy = new SqlOrderBy(orderByArguments, List.of(false, true), List.of(false, true)); + final SqlFunctionAggregateGroupConcat sqlFunctionAggregateGroupConcat = SqlFunctionAggregateGroupConcat + .builder(argument).separator(new SqlLiteralString("'")).orderBy(orderBy).build(); + assertThat(this.visitor.visit(sqlFunctionAggregateGroupConcat), equalTo("STRING_AGG(E'test', E'''') ")); + } +} \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java new file mode 100644 index 0000000..7934c65 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java @@ -0,0 +1,50 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.adapter.AdapterProperties.IGNORE_ERRORS_PROPERTY; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import com.exasol.adapter.AdapterProperties; +import com.exasol.adapter.dialects.BaseIdentifierConverter; +import com.exasol.adapter.jdbc.RemoteMetadataReaderException; + +class SnowflakeTableMetadataReaderTest { + private Map rawProperties; + private SnowflakeTableMetadataReader reader; + + @BeforeEach + void beforeEach() { + this.rawProperties = new HashMap<>(); + final AdapterProperties properties = new AdapterProperties(this.rawProperties); + this.reader = new SnowflakeTableMetadataReader(null, null, properties, + BaseIdentifierConverter.createDefault()); + } + + private void ignoreErrors(final String ignoreErrors) { + this.rawProperties.put(IGNORE_ERRORS_PROPERTY, ignoreErrors); + } + + + +/* @Test + void testIsUppercaseTableIncludedByMappingWithIgnoringUppercaseTables() { + ignoreErrors("SNOWFLAKE_UPPERCASE_TABLES"); + assertThat(this.reader.isTableIncludedByMapping("\"FooBar\""), equalTo(false)); + } + + @Test + void testIsUppercaseTableIncludedByMappingWithConvertToUpperNotIgnoringUppercaseTablesThrowsException() { + final RemoteMetadataReaderException exception = assertThrows(RemoteMetadataReaderException.class, + () -> this.reader.isTableIncludedByMapping("\"FooBar\"")); + assertThat(exception.getMessage(), containsString("E-VSSF-6")); + }*/ +} \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java b/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java new file mode 100644 index 0000000..a749989 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java @@ -0,0 +1,95 @@ +package com.exasol.adapter.dialects.snowflake.docgeneration; + +import java.nio.file.Path; +import java.util.Set; + +import com.exasol.adapter.capabilities.*; +import com.exasol.adapter.dialects.SqlDialect; +import com.exasol.adapter.dialects.SqlDialectFactory; +import com.exasol.autogeneratedresourceverifier.AutogeneratedResource; + +import net.steppschuh.markdowngenerator.table.Table; + +public class CapabilitiesReport implements AutogeneratedResource { + private final SqlDialectFactory dialectFactory; + + public CapabilitiesReport(final SqlDialectFactory dialectFactory) { + this.dialectFactory = dialectFactory; + } + + @Override + public String generateContent() { + final LinedStringBuilder reportBuilder = new LinedStringBuilder(); + final SqlDialect sqlDialect = this.dialectFactory.createSqlDialect(null, null); + final Capabilities capabilities = sqlDialect.getCapabilities(); + reportBuilder.appendLine( + " "); + reportBuilder.appendLine(); + reportBuilder.appendLine("# Capabilities"); + reportBuilder.appendLine(); + reportBuilder.appendLine( + "Capabilities tell the Exasol which SQL features / keywords a Virtual Schema adapter supports. " + + "If the Virtual Schema does not support a certain capability, Exasol rewrites the query without that feature. " + + "In case a Virtual Schema adapter has no capabilities at all, Exasol will rewrite all queries to `SELECT * FROM table`. " + + "That means, that it will always load the whole remote table, even if only a single row is requested." + + "So, for optimizing your performance, make sure that at least all functions that you use in the `WHERE` clause of your queries are supported by the Virtual Schema adapter."); + reportBuilder.appendLine(); + reportCapabilities("Main Capabilities", "Capability", MainCapability.values(), + capabilities.getMainCapabilities(), reportBuilder); + reportCapabilities("Supported Literals", "Literal", LiteralCapability.values(), + capabilities.getLiteralCapabilities(), reportBuilder); + reportCapabilities("Supported Predicates", "Predicate", PredicateCapability.values(), + capabilities.getPredicateCapabilities(), reportBuilder); + reportCapabilities("Supported Aggregate Functions", "Aggregate Function", AggregateFunctionCapability.values(), + capabilities.getAggregateFunctionCapabilities(), reportBuilder); + reportCapabilities("Supported Scalar Functions", "Scalar Function", ScalarFunctionCapability.values(), + capabilities.getScalarFunctionCapabilities(), reportBuilder); + return reportBuilder.toString(); + } + + @Override + public Path getPathOfGeneratedFile() { + return Path.of("doc", "generated", "capabilities.md"); + } + + private void reportCapabilities(final String headline, final String tableHeader, final T[] all, + final Set enabled, final LinedStringBuilder reportBuilder) { + reportBuilder.appendLine("## " + headline); + reportBuilder.appendLine(); + final Table.Builder tableBuilder = new Table.Builder().withAlignments(Table.ALIGN_LEFT, Table.ALIGN_CENTER) + .addRow(tableHeader, "Supported"); + for (final T function : all) { + tableBuilder.addRow(function, getEnabledText(enabled.contains(function))); + } + reportBuilder.appendLine(tableBuilder.build().toString()); + reportBuilder.appendLine(); + } + + private String getEnabledText(final boolean enabled) { + if (enabled) { + return "✓"; + } else { + return ""; + } + } + + private static class LinedStringBuilder { + private static final String LINE_SEPARATOR = System.lineSeparator(); + StringBuilder stringBuilder = new StringBuilder(); + + public LinedStringBuilder appendLine(final String line) { + this.stringBuilder.append(line).append(LINE_SEPARATOR); + return this; + } + + public LinedStringBuilder appendLine() { + this.stringBuilder.append(LINE_SEPARATOR); + return this; + } + + @Override + public String toString() { + return this.stringBuilder.toString(); + } + } +} diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/SnowflakeAutogeneratedResourceVerifier.java b/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/SnowflakeAutogeneratedResourceVerifier.java new file mode 100644 index 0000000..b9e1574 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/SnowflakeAutogeneratedResourceVerifier.java @@ -0,0 +1,11 @@ +package com.exasol.adapter.dialects.snowflake.docgeneration; + +import com.exasol.adapter.dialects.snowflake.SnowflakeSqlDialectFactory; +import com.exasol.autogeneratedresourceverifier.AutogeneratedResourceVerifier; + +public class SnowflakeAutogeneratedResourceVerifier { + + public static void main(final String[] args) { + new AutogeneratedResourceVerifier().verifyResource(new CapabilitiesReport(new SnowflakeSqlDialectFactory())); + } +} diff --git a/src/test/java/com/exasol/closeafterall/CloseAfterAll.java b/src/test/java/com/exasol/closeafterall/CloseAfterAll.java new file mode 100644 index 0000000..81d2191 --- /dev/null +++ b/src/test/java/com/exasol/closeafterall/CloseAfterAll.java @@ -0,0 +1,14 @@ +package com.exasol.closeafterall; + +import java.lang.annotation.*; + +/** + * This annotation marks a resource that should be closed after all tests were executed. + *

+ * In order to make this work you need to add the {@link CloseAfterAllExtension} to your test class. + *

+ */ +@Target({ ElementType.FIELD }) +@Retention(RetentionPolicy.RUNTIME) +public @interface CloseAfterAll { +} diff --git a/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java b/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java new file mode 100644 index 0000000..5b2da71 --- /dev/null +++ b/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java @@ -0,0 +1,48 @@ +package com.exasol.closeafterall; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.reflect.Field; + +import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.ExtensionContext; + +import com.exasol.errorreporting.ExaError; + +/** + * This JUnit extension closes resources in static fields that are annotated with {@code @CloseAfterAll}. You can use it + * by annotating your class with {@code @ExtendWith({ CloseAfterAllExtension.class })}. + */ +public class CloseAfterAllExtension implements AfterAllCallback { + + @Override + public void afterAll(final ExtensionContext extensionContext) { + final Class testClass = extensionContext.getRequiredTestClass(); + final Field[] fields = testClass.getClass().getDeclaredFields(); + for (final Field field : fields) { + closeField(testClass, field); + } + } + + private void closeField(final Class testClass, final Field field) { + if (field.isAnnotationPresent(CloseAfterAll.class)) { + field.setAccessible(true); + try { + final Object annotatedObject = field.get(null); + closeObject(field, annotatedObject); + } catch (final IllegalAccessException | IOException e) { + throw new IllegalStateException("Failed to close " + field.getName()); + } + } + } + + private void closeObject(final Field field, final Object annotatedObject) throws IOException { + if (annotatedObject instanceof Closeable) { + ((Closeable) annotatedObject).close(); + } else { + throw new IllegalStateException(ExaError.messageBuilder("E-VSSF-9").message( + "Could not close the field {{field}} annotated with @CloseAfterAll since it does not implement Closable.") + .parameter("field", field.getName()).toString()); + } + } +} diff --git a/src/test/resources/integration/scalarFunctionsParameterCache.yml b/src/test/resources/integration/scalarFunctionsParameterCache.yml new file mode 100644 index 0000000..cfeb94b --- /dev/null +++ b/src/test/resources/integration/scalarFunctionsParameterCache.yml @@ -0,0 +1,1517 @@ +abs: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +acos: ['"DOUBLE_PRECISION_C0"'] +add_hours: ['"DATE_C5", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1"'] +add_minutes: ['"DATE_C5", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1"'] +add_seconds: ['"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1"', '"DATE_C5", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2"'] +ascii: ['"VARCHAR2_C4"'] +asin: ['"DOUBLE_PRECISION_C0"'] +atan: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +atan2: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2"'] +bit_Length: ['"VARCHAR2_C4"'] +bit_length: ['"VARCHAR2_C4"'] +ceil: ['"DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2"'] +ceiling: ['"DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2"'] +char: ['"INTEGER_C1"'] +char_Length: ['"VARCHAR2_C4"'] +char_length: ['"VARCHAR2_C4"'] +character_Length: ['"VARCHAR2_C4"'] +character_length: ['"VARCHAR2_C4"'] +chr: ['"INTEGER_C1"'] +concat: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"', + '"VARCHAR2_C4"', '"DATE_C5"', '"TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "DATE_C5"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", + "BOOLEAN_C3"', '"INTEGER_C1", "VARCHAR2_C4"', '"INTEGER_C1", "DATE_C5"', '"INTEGER_C1", + "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3"', + '"DECIMAL18__3_C2", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", + "VARCHAR2_C4"', '"BOOLEAN_C3", "DATE_C5"', '"BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", "DATE_C5"', + '"VARCHAR2_C4", "TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3"', '"DATE_C5", + "VARCHAR2_C4"', '"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DATE_C5"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DATE_C5"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "VARCHAR2_C4", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "DATE_C5"', + '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "DATE_C5", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DATE_C5", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DATE_C5", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DATE_C5", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DATE_C5", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "DATE_C5", "DATE_C5"', '"DOUBLE_PRECISION_C0", "DATE_C5", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "DATE_C5"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", + "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", + "INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', + '"INTEGER_C1", "INTEGER_C1", "VARCHAR2_C4"', '"INTEGER_C1", "INTEGER_C1", "DATE_C5"', + '"INTEGER_C1", "INTEGER_C1", "TIMESTAMP_C6"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', '"INTEGER_C1", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"INTEGER_C1", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DATE_C5"', '"INTEGER_C1", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', + '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', + '"INTEGER_C1", "BOOLEAN_C3", "VARCHAR2_C4"', '"INTEGER_C1", "BOOLEAN_C3", "DATE_C5"', + '"INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', '"INTEGER_C1", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "VARCHAR2_C4", "INTEGER_C1"', '"INTEGER_C1", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"INTEGER_C1", "VARCHAR2_C4", "BOOLEAN_C3"', '"INTEGER_C1", "VARCHAR2_C4", "VARCHAR2_C4"', + '"INTEGER_C1", "VARCHAR2_C4", "DATE_C5"', '"INTEGER_C1", "VARCHAR2_C4", "TIMESTAMP_C6"', + '"INTEGER_C1", "DATE_C5", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DATE_C5", "INTEGER_C1"', + '"INTEGER_C1", "DATE_C5", "DECIMAL18__3_C2"', '"INTEGER_C1", "DATE_C5", "BOOLEAN_C3"', + '"INTEGER_C1", "DATE_C5", "VARCHAR2_C4"', '"INTEGER_C1", "DATE_C5", "DATE_C5"', + '"INTEGER_C1", "DATE_C5", "TIMESTAMP_C6"', '"INTEGER_C1", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "TIMESTAMP_C6", "INTEGER_C1"', '"INTEGER_C1", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"INTEGER_C1", "TIMESTAMP_C6", "BOOLEAN_C3"', '"INTEGER_C1", "TIMESTAMP_C6", "VARCHAR2_C4"', + '"INTEGER_C1", "TIMESTAMP_C6", "DATE_C5"', '"INTEGER_C1", "TIMESTAMP_C6", "TIMESTAMP_C6"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DATE_C5"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', + '"DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "VARCHAR2_C4"', '"DECIMAL18__3_C2", + "INTEGER_C1", "DATE_C5"', '"DECIMAL18__3_C2", "INTEGER_C1", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "VARCHAR2_C4"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DATE_C5"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "VARCHAR2_C4", "INTEGER_C1"', '"DECIMAL18__3_C2", "VARCHAR2_C4", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "VARCHAR2_C4", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "DATE_C5"', + '"DECIMAL18__3_C2", "VARCHAR2_C4", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DATE_C5", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DATE_C5", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DATE_C5", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DATE_C5", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DATE_C5", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DATE_C5", "DATE_C5"', '"DECIMAL18__3_C2", + "DATE_C5", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "TIMESTAMP_C6", "INTEGER_C1"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "TIMESTAMP_C6", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "DATE_C5"', + '"DECIMAL18__3_C2", "TIMESTAMP_C6", "TIMESTAMP_C6"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DATE_C5"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', + '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1", + "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', '"BOOLEAN_C3", + "INTEGER_C1", "DATE_C5"', '"BOOLEAN_C3", "INTEGER_C1", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "DATE_C5"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "TIMESTAMP_C6"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1"', '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "BOOLEAN_C3", "VARCHAR2_C4"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DATE_C5"', '"BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "VARCHAR2_C4", "INTEGER_C1"', + '"BOOLEAN_C3", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "VARCHAR2_C4", + "BOOLEAN_C3"', '"BOOLEAN_C3", "VARCHAR2_C4", "VARCHAR2_C4"', '"BOOLEAN_C3", "VARCHAR2_C4", + "DATE_C5"', '"BOOLEAN_C3", "VARCHAR2_C4", "TIMESTAMP_C6"', '"BOOLEAN_C3", "DATE_C5", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DATE_C5", "INTEGER_C1"', '"BOOLEAN_C3", + "DATE_C5", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DATE_C5", "BOOLEAN_C3"', '"BOOLEAN_C3", + "DATE_C5", "VARCHAR2_C4"', '"BOOLEAN_C3", "DATE_C5", "DATE_C5"', '"BOOLEAN_C3", + "DATE_C5", "TIMESTAMP_C6"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "INTEGER_C1"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "BOOLEAN_C3"', '"BOOLEAN_C3", "TIMESTAMP_C6", "VARCHAR2_C4"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "DATE_C5"', '"BOOLEAN_C3", "TIMESTAMP_C6", "TIMESTAMP_C6"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DATE_C5"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "TIMESTAMP_C6"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", "VARCHAR2_C4"', + '"VARCHAR2_C4", "INTEGER_C1", "DATE_C5"', '"VARCHAR2_C4", "INTEGER_C1", "TIMESTAMP_C6"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "DATE_C5"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "BOOLEAN_C3", "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "BOOLEAN_C3", "VARCHAR2_C4"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DATE_C5"', '"VARCHAR2_C4", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"VARCHAR2_C4", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "VARCHAR2_C4", + "INTEGER_C1"', '"VARCHAR2_C4", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", + "VARCHAR2_C4", "DATE_C5"', '"VARCHAR2_C4", "VARCHAR2_C4", "TIMESTAMP_C6"', '"VARCHAR2_C4", + "DATE_C5", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DATE_C5", "INTEGER_C1"', '"VARCHAR2_C4", + "DATE_C5", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DATE_C5", "BOOLEAN_C3"', '"VARCHAR2_C4", + "DATE_C5", "VARCHAR2_C4"', '"VARCHAR2_C4", "DATE_C5", "DATE_C5"', '"VARCHAR2_C4", + "DATE_C5", "TIMESTAMP_C6"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "INTEGER_C1"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "BOOLEAN_C3"', '"VARCHAR2_C4", "TIMESTAMP_C6", "VARCHAR2_C4"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "DATE_C5"', '"VARCHAR2_C4", "TIMESTAMP_C6", "TIMESTAMP_C6"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"DATE_C5", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "TIMESTAMP_C6"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "INTEGER_C1", "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", + "INTEGER_C1", "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "VARCHAR2_C4"', '"DATE_C5", + "INTEGER_C1", "DATE_C5"', '"DATE_C5", "INTEGER_C1", "TIMESTAMP_C6"', '"DATE_C5", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DATE_C5", "DECIMAL18__3_C2", "INTEGER_C1"', + '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DATE_C5", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DATE_C5", "DECIMAL18__3_C2", + "DATE_C5"', '"DATE_C5", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DATE_C5", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", + "VARCHAR2_C4"', '"DATE_C5", "BOOLEAN_C3", "DATE_C5"', '"DATE_C5", "BOOLEAN_C3", + "TIMESTAMP_C6"', '"DATE_C5", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "VARCHAR2_C4", "INTEGER_C1"', '"DATE_C5", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DATE_C5", + "VARCHAR2_C4", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4", "VARCHAR2_C4"', '"DATE_C5", + "VARCHAR2_C4", "DATE_C5"', '"DATE_C5", "VARCHAR2_C4", "TIMESTAMP_C6"', '"DATE_C5", + "DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", "DATE_C5", "INTEGER_C1"', '"DATE_C5", + "DATE_C5", "DECIMAL18__3_C2"', '"DATE_C5", "DATE_C5", "BOOLEAN_C3"', '"DATE_C5", + "DATE_C5", "VARCHAR2_C4"', '"DATE_C5", "DATE_C5", "DATE_C5"', '"DATE_C5", "DATE_C5", + "TIMESTAMP_C6"', '"DATE_C5", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "TIMESTAMP_C6", "INTEGER_C1"', '"DATE_C5", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"DATE_C5", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DATE_C5", "TIMESTAMP_C6", "VARCHAR2_C4"', + '"DATE_C5", "TIMESTAMP_C6", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6", "TIMESTAMP_C6"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DATE_C5"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1", "INTEGER_C1"', + '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "INTEGER_C1", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "INTEGER_C1", "DATE_C5"', '"TIMESTAMP_C6", "INTEGER_C1", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DATE_C5"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "BOOLEAN_C3", "VARCHAR2_C4"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DATE_C5"', '"TIMESTAMP_C6", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "VARCHAR2_C4", + "INTEGER_C1"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "VARCHAR2_C4", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4", "VARCHAR2_C4"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "DATE_C5"', '"TIMESTAMP_C6", "VARCHAR2_C4", "TIMESTAMP_C6"', + '"TIMESTAMP_C6", "DATE_C5", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DATE_C5", + "INTEGER_C1"', '"TIMESTAMP_C6", "DATE_C5", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "DATE_C5", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DATE_C5", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "DATE_C5", "DATE_C5"', '"TIMESTAMP_C6", "DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "INTEGER_C1"', + '"TIMESTAMP_C6", "TIMESTAMP_C6", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "TIMESTAMP_C6", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "TIMESTAMP_C6", "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "TIMESTAMP_C6"'] +cos: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +cosh: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +cot: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +curdate: [''] +current_schema_id: [''] +day: ['"DATE_C5"', '"TIMESTAMP_C6"'] +days_between: ['"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"'] +degrees: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +div: ['"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2"'] +dump: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"', + '"VARCHAR2_C4"', '"DATE_C5"', '"TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"INTEGER_C1", + "INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', + '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"INTEGER_C1", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "INTEGER_C1", + "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3", "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2"'] +exp: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +floor: ['"DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2"'] +from_posix_time: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"'] +hour: ['"DATE_C5"', '"TIMESTAMP_C6"'] +hours_between: ['"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"'] +insert: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "DATE_C5"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1", "TIMESTAMP_C6"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1", "DATE_C5"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "INTEGER_C1", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DECIMAL18__3_C2", "DATE_C5"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3", + "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3", "DATE_C5"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "INTEGER_C1", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "INTEGER_C1", "DATE_C5"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "INTEGER_C1", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DECIMAL18__3_C2", "DATE_C5"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3", + "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3", "DATE_C5"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "VARCHAR2_C4"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1", "VARCHAR2_C4"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DATE_C5"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DATE_C5"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "VARCHAR2_C4"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', '"INTEGER_C1", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"INTEGER_C1", "INTEGER_C1", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"INTEGER_C1", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', '"INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1", + "INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1", "VARCHAR2_C4"', + '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1", "DATE_C5"', '"INTEGER_C1", "INTEGER_C1", + "INTEGER_C1", "TIMESTAMP_C6"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', + '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"INTEGER_C1", + "INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2", + "VARCHAR2_C4"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2", "DATE_C5"', '"INTEGER_C1", + "INTEGER_C1", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"INTEGER_C1", "INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3", + "INTEGER_C1"', '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', '"INTEGER_C1", "INTEGER_C1", + "BOOLEAN_C3", "VARCHAR2_C4"', '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3", "DATE_C5"', + '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"INTEGER_C1", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DATE_C5"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", + "DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", "DECIMAL18__3_C2", + "INTEGER_C1", "VARCHAR2_C4"', '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1", + "DATE_C5"', '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1", "TIMESTAMP_C6"', '"INTEGER_C1", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"INTEGER_C1", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DATE_C5"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', + '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"INTEGER_C1", + "DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"INTEGER_C1", "DECIMAL18__3_C2", + "BOOLEAN_C3", "VARCHAR2_C4"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3", + "DATE_C5"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3", "TIMESTAMP_C6"', '"INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DATE_C5"', '"INTEGER_C1", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3", + "INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', + '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1", "DATE_C5"', '"INTEGER_C1", "BOOLEAN_C3", + "INTEGER_C1", "TIMESTAMP_C6"', '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', + '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"INTEGER_C1", + "BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2", + "VARCHAR2_C4"', '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2", "DATE_C5"', '"INTEGER_C1", + "BOOLEAN_C3", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"INTEGER_C1", "BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1"', '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', '"INTEGER_C1", "BOOLEAN_C3", + "BOOLEAN_C3", "VARCHAR2_C4"', '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3", "DATE_C5"', + '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1", "DATE_C5"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DECIMAL18__3_C2", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1", + "VARCHAR2_C4"', '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1", "DATE_C5"', '"DECIMAL18__3_C2", + "INTEGER_C1", "INTEGER_C1", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "INTEGER_C1", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", + "INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3", "DATE_C5"', '"DECIMAL18__3_C2", + "INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1", "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "INTEGER_C1", "VARCHAR2_C4"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "INTEGER_C1", "DATE_C5"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3", + "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3", "DATE_C5"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1", + "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "INTEGER_C1", "DATE_C5"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1", "TIMESTAMP_C6"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "BOOLEAN_C3", "BOOLEAN_C3", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "BOOLEAN_C3", "DATE_C5"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DATE_C5"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "BOOLEAN_C3"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1", "VARCHAR2_C4"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1", "DATE_C5"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "TIMESTAMP_C6"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DATE_C5"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "VARCHAR2_C4"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', + '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"BOOLEAN_C3", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', '"BOOLEAN_C3", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "INTEGER_C1", + "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1", "VARCHAR2_C4"', + '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1", "DATE_C5"', '"BOOLEAN_C3", "INTEGER_C1", + "INTEGER_C1", "TIMESTAMP_C6"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', + '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2", + "VARCHAR2_C4"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2", "DATE_C5"', '"BOOLEAN_C3", + "INTEGER_C1", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"BOOLEAN_C3", "INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3", + "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", + "BOOLEAN_C3", "VARCHAR2_C4"', '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3", "DATE_C5"', + '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DATE_C5"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "INTEGER_C1", "VARCHAR2_C4"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1", + "DATE_C5"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DATE_C5"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "BOOLEAN_C3", "VARCHAR2_C4"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3", + "DATE_C5"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DATE_C5"', '"BOOLEAN_C3", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', + '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', + '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1", "DATE_C5"', '"BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1", "TIMESTAMP_C6"', '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2", + "VARCHAR2_C4"', '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2", "DATE_C5"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"BOOLEAN_C3", "BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "BOOLEAN_C3", + "BOOLEAN_C3", "VARCHAR2_C4"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3", "DATE_C5"', + '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1", "VARCHAR2_C4"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DATE_C5"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "TIMESTAMP_C6"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DATE_C5"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "VARCHAR2_C4"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"VARCHAR2_C4", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', '"VARCHAR2_C4", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1", + "VARCHAR2_C4"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1", "DATE_C5"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1", "TIMESTAMP_C6"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', + '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", + "DECIMAL18__3_C2", "VARCHAR2_C4"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2", + "DATE_C5"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2", "TIMESTAMP_C6"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3", "VARCHAR2_C4"', '"VARCHAR2_C4", "INTEGER_C1", + "BOOLEAN_C3", "DATE_C5"', '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DATE_C5"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "INTEGER_C1", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1", + "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1", "VARCHAR2_C4"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1", "DATE_C5"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "INTEGER_C1", "TIMESTAMP_C6"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DATE_C5"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3", + "VARCHAR2_C4"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3", "DATE_C5"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"VARCHAR2_C4", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"VARCHAR2_C4", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DATE_C5"', '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "TIMESTAMP_C6"', '"VARCHAR2_C4", "BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", + "INTEGER_C1", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "BOOLEAN_C3", "INTEGER_C1", + "BOOLEAN_C3"', '"VARCHAR2_C4", "BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', '"VARCHAR2_C4", + "BOOLEAN_C3", "INTEGER_C1", "DATE_C5"', '"VARCHAR2_C4", "BOOLEAN_C3", "INTEGER_C1", + "TIMESTAMP_C6"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"VARCHAR2_C4", + "BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "BOOLEAN_C3", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2", + "VARCHAR2_C4"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2", "DATE_C5"', '"VARCHAR2_C4", + "BOOLEAN_C3", "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"VARCHAR2_C4", "BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "BOOLEAN_C3", "BOOLEAN_C3", + "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "BOOLEAN_C3", + "BOOLEAN_C3", "VARCHAR2_C4"', '"VARCHAR2_C4", "BOOLEAN_C3", "BOOLEAN_C3", "DATE_C5"', + '"VARCHAR2_C4", "BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DATE_C5", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "INTEGER_C1"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "VARCHAR2_C4"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "DATE_C5"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1", "TIMESTAMP_C6"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DATE_C5", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DATE_C5"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', + '"DATE_C5", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "VARCHAR2_C4"', '"DATE_C5", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DATE_C5"', '"DATE_C5", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DATE_C5", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DATE_C5", "INTEGER_C1", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"DATE_C5", "INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", + "INTEGER_C1", "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "INTEGER_C1", "VARCHAR2_C4"', + '"DATE_C5", "INTEGER_C1", "INTEGER_C1", "DATE_C5"', '"DATE_C5", "INTEGER_C1", "INTEGER_C1", + "TIMESTAMP_C6"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DATE_C5", + "INTEGER_C1", "DECIMAL18__3_C2", "DATE_C5"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DATE_C5", "INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', + '"DATE_C5", "INTEGER_C1", "BOOLEAN_C3", "VARCHAR2_C4"', '"DATE_C5", "INTEGER_C1", + "BOOLEAN_C3", "DATE_C5"', '"DATE_C5", "INTEGER_C1", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DATE_C5", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DATE_C5", "DECIMAL18__3_C2", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', + '"DATE_C5", "DECIMAL18__3_C2", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "DECIMAL18__3_C2", + "INTEGER_C1", "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "INTEGER_C1", "VARCHAR2_C4"', + '"DATE_C5", "DECIMAL18__3_C2", "INTEGER_C1", "DATE_C5"', '"DATE_C5", "DECIMAL18__3_C2", + "INTEGER_C1", "TIMESTAMP_C6"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "INTEGER_C1"', + '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DATE_C5", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DATE_C5"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "TIMESTAMP_C6"', + '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3", "VARCHAR2_C4"', '"DATE_C5", + "DECIMAL18__3_C2", "BOOLEAN_C3", "DATE_C5"', '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3", + "TIMESTAMP_C6"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DATE_C5"', '"DATE_C5", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', + '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3", + "INTEGER_C1", "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1", "VARCHAR2_C4"', + '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1", "DATE_C5"', '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1", + "TIMESTAMP_C6"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2", + "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"DATE_C5", + "BOOLEAN_C3", "DECIMAL18__3_C2", "DATE_C5"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', + '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3", "VARCHAR2_C4"', '"DATE_C5", "BOOLEAN_C3", + "BOOLEAN_C3", "DATE_C5"', '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3", "TIMESTAMP_C6"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DATE_C5"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "INTEGER_C1", "DATE_C5"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "INTEGER_C1", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DATE_C5"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "VARCHAR2_C4"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DATE_C5"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "BOOLEAN_C3", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0", "DATE_C5"', '"TIMESTAMP_C6", + "INTEGER_C1", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "INTEGER_C1", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1", "INTEGER_C1", + "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", + "INTEGER_C1", "VARCHAR2_C4"', '"TIMESTAMP_C6", "INTEGER_C1", "INTEGER_C1", "DATE_C5"', + '"TIMESTAMP_C6", "INTEGER_C1", "INTEGER_C1", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "INTEGER_C1", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2", + "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "INTEGER_C1", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"TIMESTAMP_C6", "INTEGER_C1", + "DECIMAL18__3_C2", "DATE_C5"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "INTEGER_C1", "BOOLEAN_C3", "DATE_C5"', '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DATE_C5"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "INTEGER_C1", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1", "VARCHAR2_C4"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1", "DATE_C5"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "INTEGER_C1", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DATE_C5"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3", + "VARCHAR2_C4"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3", "DATE_C5"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DATE_C5"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "BOOLEAN_C3", "INTEGER_C1", + "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "INTEGER_C1", "VARCHAR2_C4"', '"TIMESTAMP_C6", "BOOLEAN_C3", "INTEGER_C1", "DATE_C5"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "INTEGER_C1", "TIMESTAMP_C6"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2", + "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "DECIMAL18__3_C2", "VARCHAR2_C4"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "DECIMAL18__3_C2", "DATE_C5"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "BOOLEAN_C3", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "BOOLEAN_C3", "BOOLEAN_C3", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "BOOLEAN_C3", "BOOLEAN_C3", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "BOOLEAN_C3", "DATE_C5"', '"TIMESTAMP_C6", "BOOLEAN_C3", "BOOLEAN_C3", + "TIMESTAMP_C6"'] +instr: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", + "VARCHAR2_C4"', '"INTEGER_C1", "DATE_C5"', '"INTEGER_C1", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "VARCHAR2_C4"', '"BOOLEAN_C3", "DATE_C5"', + '"BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "BOOLEAN_C3"', + '"VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", "DATE_C5"', '"VARCHAR2_C4", "TIMESTAMP_C6"', + '"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2"', + '"DATE_C5", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4"', '"DATE_C5", "DATE_C5"', '"DATE_C5", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "VARCHAR2_C4"', '"TIMESTAMP_C6", "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "VARCHAR2_C4", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "DATE_C5", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DATE_C5", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DATE_C5", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6", "BOOLEAN_C3"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"INTEGER_C1", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', + '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", + "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"INTEGER_C1", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', '"INTEGER_C1", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "VARCHAR2_C4", "INTEGER_C1"', '"INTEGER_C1", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"INTEGER_C1", "VARCHAR2_C4", "BOOLEAN_C3"', '"INTEGER_C1", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DATE_C5", "INTEGER_C1"', '"INTEGER_C1", "DATE_C5", "DECIMAL18__3_C2"', + '"INTEGER_C1", "DATE_C5", "BOOLEAN_C3"', '"INTEGER_C1", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "TIMESTAMP_C6", "INTEGER_C1"', '"INTEGER_C1", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"INTEGER_C1", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "INTEGER_C1"', + '"DECIMAL18__3_C2", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "VARCHAR2_C4", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DATE_C5", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DATE_C5", "INTEGER_C1"', '"DECIMAL18__3_C2", "DATE_C5", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DATE_C5", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "TIMESTAMP_C6", "INTEGER_C1"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "BOOLEAN_C3"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', + '"BOOLEAN_C3", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "VARCHAR2_C4", + "INTEGER_C1"', '"BOOLEAN_C3", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "VARCHAR2_C4", "BOOLEAN_C3"', '"BOOLEAN_C3", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DATE_C5", "INTEGER_C1"', '"BOOLEAN_C3", "DATE_C5", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "DATE_C5", "BOOLEAN_C3"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "INTEGER_C1"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "BOOLEAN_C3", + "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DATE_C5", "INTEGER_C1"', '"VARCHAR2_C4", "DATE_C5", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "DATE_C5", "BOOLEAN_C3"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "INTEGER_C1"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1", + "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "VARCHAR2_C4", "INTEGER_C1"', '"DATE_C5", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"DATE_C5", "VARCHAR2_C4", "BOOLEAN_C3"', '"DATE_C5", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "DATE_C5", "INTEGER_C1"', '"DATE_C5", "DATE_C5", "DECIMAL18__3_C2"', + '"DATE_C5", "DATE_C5", "BOOLEAN_C3"', '"DATE_C5", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "TIMESTAMP_C6", "INTEGER_C1"', '"DATE_C5", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"DATE_C5", "TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "INTEGER_C1", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "INTEGER_C1"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DATE_C5", "INTEGER_C1"', '"TIMESTAMP_C6", "DATE_C5", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "DATE_C5", "BOOLEAN_C3"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "BOOLEAN_C3"'] +iproc: [''] +is_number: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"VARCHAR2_C4"'] +lcase: ['"VARCHAR2_C4"'] +left: ['"VARCHAR2_C4", "INTEGER_C1"'] +length: ['"VARCHAR2_C4"'] +ln: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +locate: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", "DATE_C5"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", + "VARCHAR2_C4"', '"INTEGER_C1", "DATE_C5"', '"INTEGER_C1", "TIMESTAMP_C6"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "VARCHAR2_C4"', + '"DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", "TIMESTAMP_C6"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", "VARCHAR2_C4"', '"BOOLEAN_C3", "DATE_C5"', + '"BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "BOOLEAN_C3"', + '"VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", "DATE_C5"', '"VARCHAR2_C4", "TIMESTAMP_C6"', + '"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2"', + '"DATE_C5", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4"', '"DATE_C5", "DATE_C5"', '"DATE_C5", + "TIMESTAMP_C6"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1"', + '"TIMESTAMP_C6", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "VARCHAR2_C4"', '"TIMESTAMP_C6", "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "VARCHAR2_C4", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "DATE_C5", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DATE_C5", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DATE_C5", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "TIMESTAMP_C6", "BOOLEAN_C3"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"INTEGER_C1", + "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', + '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DECIMAL18__3_C2", + "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"INTEGER_C1", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', '"INTEGER_C1", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "VARCHAR2_C4", "INTEGER_C1"', '"INTEGER_C1", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"INTEGER_C1", "VARCHAR2_C4", "BOOLEAN_C3"', '"INTEGER_C1", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DATE_C5", "INTEGER_C1"', '"INTEGER_C1", "DATE_C5", "DECIMAL18__3_C2"', + '"INTEGER_C1", "DATE_C5", "BOOLEAN_C3"', '"INTEGER_C1", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "TIMESTAMP_C6", "INTEGER_C1"', '"INTEGER_C1", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"INTEGER_C1", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "INTEGER_C1"', + '"DECIMAL18__3_C2", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "VARCHAR2_C4", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DATE_C5", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DATE_C5", "INTEGER_C1"', '"DECIMAL18__3_C2", "DATE_C5", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DATE_C5", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "TIMESTAMP_C6", "INTEGER_C1"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "BOOLEAN_C3"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', + '"BOOLEAN_C3", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "VARCHAR2_C4", + "INTEGER_C1"', '"BOOLEAN_C3", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "VARCHAR2_C4", "BOOLEAN_C3"', '"BOOLEAN_C3", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DATE_C5", "INTEGER_C1"', '"BOOLEAN_C3", "DATE_C5", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "DATE_C5", "BOOLEAN_C3"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "INTEGER_C1"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "BOOLEAN_C3", + "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DATE_C5", "INTEGER_C1"', '"VARCHAR2_C4", "DATE_C5", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "DATE_C5", "BOOLEAN_C3"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "INTEGER_C1"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1", + "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "VARCHAR2_C4", "INTEGER_C1"', '"DATE_C5", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"DATE_C5", "VARCHAR2_C4", "BOOLEAN_C3"', '"DATE_C5", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "DATE_C5", "INTEGER_C1"', '"DATE_C5", "DATE_C5", "DECIMAL18__3_C2"', + '"DATE_C5", "DATE_C5", "BOOLEAN_C3"', '"DATE_C5", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "TIMESTAMP_C6", "INTEGER_C1"', '"DATE_C5", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"DATE_C5", "TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "INTEGER_C1", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "INTEGER_C1"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DATE_C5", "INTEGER_C1"', '"TIMESTAMP_C6", "DATE_C5", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "DATE_C5", "BOOLEAN_C3"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "BOOLEAN_C3"'] +log: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"INTEGER_C1", + "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1"', + '"DECIMAL18__3_C2", "DECIMAL18__3_C2"'] +log10: ['"INTEGER_C1"', '"DECIMAL18__3_C2"'] +log2: ['"INTEGER_C1"', '"DECIMAL18__3_C2"'] +lower: ['"VARCHAR2_C4"'] +lpad: ['"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "VARCHAR2_C4"'] +ltrim: ['"VARCHAR2_C4"', '"VARCHAR2_C4", "VARCHAR2_C4"'] +mid: ['"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1"'] +minute: ['"DATE_C5"', '"TIMESTAMP_C6"'] +minutes_between: ['"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"'] +mod: ['"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2"'] +month: ['"DATE_C5"', '"TIMESTAMP_C6"'] +months_between: ['"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"'] +nproc: [''] +octet_Length: ['"VARCHAR2_C4"'] +octet_length: ['"VARCHAR2_C4"'] +pi: [''] +power: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2"'] +radians: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +regexp_instr: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "DATE_C5"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", + "BOOLEAN_C3"', '"INTEGER_C1", "VARCHAR2_C4"', '"INTEGER_C1", "DATE_C5"', '"INTEGER_C1", + "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3"', + '"DECIMAL18__3_C2", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", + "VARCHAR2_C4"', '"BOOLEAN_C3", "DATE_C5"', '"BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", "DATE_C5"', + '"VARCHAR2_C4", "TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3"', '"DATE_C5", + "VARCHAR2_C4"', '"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "DATE_C5", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DATE_C5", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DATE_C5", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DATE_C5", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "BOOLEAN_C3"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"INTEGER_C1", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', + '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', + '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', + '"INTEGER_C1", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "VARCHAR2_C4", + "INTEGER_C1"', '"INTEGER_C1", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"INTEGER_C1", + "VARCHAR2_C4", "BOOLEAN_C3"', '"INTEGER_C1", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DATE_C5", "INTEGER_C1"', '"INTEGER_C1", "DATE_C5", "DECIMAL18__3_C2"', + '"INTEGER_C1", "DATE_C5", "BOOLEAN_C3"', '"INTEGER_C1", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "TIMESTAMP_C6", "INTEGER_C1"', '"INTEGER_C1", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"INTEGER_C1", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "INTEGER_C1"', + '"DECIMAL18__3_C2", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "VARCHAR2_C4", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DATE_C5", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DATE_C5", "INTEGER_C1"', '"DECIMAL18__3_C2", "DATE_C5", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DATE_C5", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "TIMESTAMP_C6", "INTEGER_C1"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "BOOLEAN_C3"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', + '"BOOLEAN_C3", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "VARCHAR2_C4", + "INTEGER_C1"', '"BOOLEAN_C3", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "VARCHAR2_C4", "BOOLEAN_C3"', '"BOOLEAN_C3", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DATE_C5", "INTEGER_C1"', '"BOOLEAN_C3", "DATE_C5", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "DATE_C5", "BOOLEAN_C3"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "INTEGER_C1"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "BOOLEAN_C3", + "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DATE_C5", "INTEGER_C1"', '"VARCHAR2_C4", "DATE_C5", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "DATE_C5", "BOOLEAN_C3"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "INTEGER_C1"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1", + "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "VARCHAR2_C4", "INTEGER_C1"', '"DATE_C5", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"DATE_C5", "VARCHAR2_C4", "BOOLEAN_C3"', '"DATE_C5", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "DATE_C5", "INTEGER_C1"', '"DATE_C5", "DATE_C5", "DECIMAL18__3_C2"', + '"DATE_C5", "DATE_C5", "BOOLEAN_C3"', '"DATE_C5", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "TIMESTAMP_C6", "INTEGER_C1"', '"DATE_C5", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"DATE_C5", "TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "INTEGER_C1", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "INTEGER_C1"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DATE_C5", "INTEGER_C1"', '"TIMESTAMP_C6", "DATE_C5", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "DATE_C5", "BOOLEAN_C3"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "BOOLEAN_C3"'] +regexp_replace: ['"VARCHAR2_C4", "VARCHAR2_C4", "VARCHAR2_C4"'] +regexp_substr: ['"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4"', '"DOUBLE_PRECISION_C0", + "DATE_C5"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", + "BOOLEAN_C3"', '"INTEGER_C1", "VARCHAR2_C4"', '"INTEGER_C1", "DATE_C5"', '"INTEGER_C1", + "TIMESTAMP_C6"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3"', + '"DECIMAL18__3_C2", "VARCHAR2_C4"', '"DECIMAL18__3_C2", "DATE_C5"', '"DECIMAL18__3_C2", + "TIMESTAMP_C6"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3"', '"BOOLEAN_C3", + "VARCHAR2_C4"', '"BOOLEAN_C3", "DATE_C5"', '"BOOLEAN_C3", "TIMESTAMP_C6"', '"VARCHAR2_C4", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", "DATE_C5"', + '"VARCHAR2_C4", "TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3"', '"DATE_C5", + "VARCHAR2_C4"', '"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "INTEGER_C1", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "INTEGER_C1", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4", "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", + "DATE_C5", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", "DATE_C5", "INTEGER_C1"', + '"DOUBLE_PRECISION_C0", "DATE_C5", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "DATE_C5", + "BOOLEAN_C3"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "TIMESTAMP_C6", "BOOLEAN_C3"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"INTEGER_C1", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"INTEGER_C1", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"INTEGER_C1", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "INTEGER_C1", "INTEGER_C1"', '"INTEGER_C1", "INTEGER_C1", "DECIMAL18__3_C2"', + '"INTEGER_C1", "INTEGER_C1", "BOOLEAN_C3"', '"INTEGER_C1", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DECIMAL18__3_C2", "INTEGER_C1"', '"INTEGER_C1", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"INTEGER_C1", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"INTEGER_C1", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "BOOLEAN_C3", "INTEGER_C1"', + '"INTEGER_C1", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3", "BOOLEAN_C3"', + '"INTEGER_C1", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "VARCHAR2_C4", + "INTEGER_C1"', '"INTEGER_C1", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"INTEGER_C1", + "VARCHAR2_C4", "BOOLEAN_C3"', '"INTEGER_C1", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "DATE_C5", "INTEGER_C1"', '"INTEGER_C1", "DATE_C5", "DECIMAL18__3_C2"', + '"INTEGER_C1", "DATE_C5", "BOOLEAN_C3"', '"INTEGER_C1", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"INTEGER_C1", "TIMESTAMP_C6", "INTEGER_C1"', '"INTEGER_C1", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"INTEGER_C1", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"DECIMAL18__3_C2", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "INTEGER_C1", "INTEGER_C1"', '"DECIMAL18__3_C2", "INTEGER_C1", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", + "INTEGER_C1"', '"DECIMAL18__3_C2", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "BOOLEAN_C3", "INTEGER_C1"', '"DECIMAL18__3_C2", "BOOLEAN_C3", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "VARCHAR2_C4", "INTEGER_C1"', + '"DECIMAL18__3_C2", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "VARCHAR2_C4", + "BOOLEAN_C3"', '"DECIMAL18__3_C2", "DATE_C5", "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", + "DATE_C5", "INTEGER_C1"', '"DECIMAL18__3_C2", "DATE_C5", "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", + "DATE_C5", "BOOLEAN_C3"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DECIMAL18__3_C2", "TIMESTAMP_C6", "INTEGER_C1"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "TIMESTAMP_C6", "BOOLEAN_C3"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"BOOLEAN_C3", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "DOUBLE_PRECISION_C0", "BOOLEAN_C3"', '"BOOLEAN_C3", "INTEGER_C1", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "INTEGER_C1", "INTEGER_C1"', '"BOOLEAN_C3", "INTEGER_C1", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "INTEGER_C1", "BOOLEAN_C3"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DECIMAL18__3_C2", "INTEGER_C1"', '"BOOLEAN_C3", "DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"BOOLEAN_C3", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"BOOLEAN_C3", + "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "BOOLEAN_C3", "INTEGER_C1"', + '"BOOLEAN_C3", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"BOOLEAN_C3", "BOOLEAN_C3", "BOOLEAN_C3"', + '"BOOLEAN_C3", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', '"BOOLEAN_C3", "VARCHAR2_C4", + "INTEGER_C1"', '"BOOLEAN_C3", "VARCHAR2_C4", "DECIMAL18__3_C2"', '"BOOLEAN_C3", + "VARCHAR2_C4", "BOOLEAN_C3"', '"BOOLEAN_C3", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "DATE_C5", "INTEGER_C1"', '"BOOLEAN_C3", "DATE_C5", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "DATE_C5", "BOOLEAN_C3"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "INTEGER_C1"', '"BOOLEAN_C3", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"BOOLEAN_C3", "TIMESTAMP_C6", "BOOLEAN_C3"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"VARCHAR2_C4", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", + "INTEGER_C1", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "INTEGER_C1", "BOOLEAN_C3"', '"VARCHAR2_C4", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "INTEGER_C1"', '"VARCHAR2_C4", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"VARCHAR2_C4", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"VARCHAR2_C4", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"VARCHAR2_C4", "BOOLEAN_C3", + "INTEGER_C1"', '"VARCHAR2_C4", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"VARCHAR2_C4", + "BOOLEAN_C3", "BOOLEAN_C3"', '"VARCHAR2_C4", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "VARCHAR2_C4", "BOOLEAN_C3"', '"VARCHAR2_C4", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "DATE_C5", "INTEGER_C1"', '"VARCHAR2_C4", "DATE_C5", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "DATE_C5", "BOOLEAN_C3"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "INTEGER_C1"', '"VARCHAR2_C4", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"VARCHAR2_C4", "TIMESTAMP_C6", "BOOLEAN_C3"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"DATE_C5", "DOUBLE_PRECISION_C0", "INTEGER_C1"', '"DATE_C5", + "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DATE_C5", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"DATE_C5", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"DATE_C5", "INTEGER_C1", + "INTEGER_C1"', '"DATE_C5", "INTEGER_C1", "DECIMAL18__3_C2"', '"DATE_C5", "INTEGER_C1", + "BOOLEAN_C3"', '"DATE_C5", "DECIMAL18__3_C2", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "DECIMAL18__3_C2", "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2", "DECIMAL18__3_C2"', + '"DATE_C5", "DECIMAL18__3_C2", "BOOLEAN_C3"', '"DATE_C5", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "BOOLEAN_C3", "INTEGER_C1"', '"DATE_C5", "BOOLEAN_C3", "DECIMAL18__3_C2"', + '"DATE_C5", "BOOLEAN_C3", "BOOLEAN_C3"', '"DATE_C5", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "VARCHAR2_C4", "INTEGER_C1"', '"DATE_C5", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"DATE_C5", "VARCHAR2_C4", "BOOLEAN_C3"', '"DATE_C5", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "DATE_C5", "INTEGER_C1"', '"DATE_C5", "DATE_C5", "DECIMAL18__3_C2"', + '"DATE_C5", "DATE_C5", "BOOLEAN_C3"', '"DATE_C5", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"DATE_C5", "TIMESTAMP_C6", "INTEGER_C1"', '"DATE_C5", "TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"DATE_C5", "TIMESTAMP_C6", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "INTEGER_C1"', + '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"TIMESTAMP_C6", "INTEGER_C1", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", + "INTEGER_C1", "INTEGER_C1"', '"TIMESTAMP_C6", "INTEGER_C1", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "INTEGER_C1", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "INTEGER_C1"', '"TIMESTAMP_C6", + "DECIMAL18__3_C2", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "DECIMAL18__3_C2", "BOOLEAN_C3"', + '"TIMESTAMP_C6", "BOOLEAN_C3", "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "BOOLEAN_C3", + "INTEGER_C1"', '"TIMESTAMP_C6", "BOOLEAN_C3", "DECIMAL18__3_C2"', '"TIMESTAMP_C6", + "BOOLEAN_C3", "BOOLEAN_C3"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "INTEGER_C1"', '"TIMESTAMP_C6", "VARCHAR2_C4", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "VARCHAR2_C4", "BOOLEAN_C3"', '"TIMESTAMP_C6", "DATE_C5", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "DATE_C5", "INTEGER_C1"', '"TIMESTAMP_C6", "DATE_C5", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "DATE_C5", "BOOLEAN_C3"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "DOUBLE_PRECISION_C0"', + '"TIMESTAMP_C6", "TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "TIMESTAMP_C6", + "DECIMAL18__3_C2"', '"TIMESTAMP_C6", "TIMESTAMP_C6", "BOOLEAN_C3"'] +repeat: ['"VARCHAR2_C4", "INTEGER_C1"'] +replace: ['"VARCHAR2_C4", "VARCHAR2_C4"', '"VARCHAR2_C4", "VARCHAR2_C4", "VARCHAR2_C4"'] +reverse: ['"VARCHAR2_C4"'] +right: ['"VARCHAR2_C4", "INTEGER_C1"'] +round: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"DATE_C5"', + '"TIMESTAMP_C6"', '"DOUBLE_PRECISION_C0", "DOUBLE_PRECISION_C0"', '"DOUBLE_PRECISION_C0", + "INTEGER_C1"', '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", + "BOOLEAN_C3"', '"INTEGER_C1", "DOUBLE_PRECISION_C0"', '"INTEGER_C1", "INTEGER_C1"', + '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "BOOLEAN_C3"', '"DECIMAL18__3_C2", + "DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2", "INTEGER_C1"', '"DECIMAL18__3_C2", + "DECIMAL18__3_C2"', '"DECIMAL18__3_C2", "BOOLEAN_C3"'] +rpad: ['"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "VARCHAR2_C4"'] +rtrim: ['"VARCHAR2_C4"', '"VARCHAR2_C4", "VARCHAR2_C4"'] +second: ['"DATE_C5"', '"TIMESTAMP_C6"', '"DATE_C5", "DOUBLE_PRECISION_C0"', '"DATE_C5", + "INTEGER_C1"', '"DATE_C5", "DECIMAL18__3_C2"', '"DATE_C5", "BOOLEAN_C3"', '"TIMESTAMP_C6", + "DOUBLE_PRECISION_C0"', '"TIMESTAMP_C6", "INTEGER_C1"', '"TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "BOOLEAN_C3"'] +seconds_between: ['"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"'] +sign: ['"DECIMAL18__3_C2"'] +sin: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +sinh: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +soundex: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"', + '"VARCHAR2_C4"', '"DATE_C5"', '"TIMESTAMP_C6"'] +space: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"'] +sqrt: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +substr: ['"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1"'] +substring: ['"VARCHAR2_C4", "INTEGER_C1"', '"VARCHAR2_C4", "INTEGER_C1", "INTEGER_C1"'] +tan: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +tanh: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"'] +to_char: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"', + '"VARCHAR2_C4"', '"DATE_C5"', '"TIMESTAMP_C6"'] +to_date: ['"DATE_C5"', '"TIMESTAMP_C6"', '"DATE_C5", "DECIMAL18__3_C2"', '"DATE_C5", + "VARCHAR2_C4"'] +to_number: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"', + '"DOUBLE_PRECISION_C0", "DECIMAL18__3_C2"', '"DOUBLE_PRECISION_C0", "VARCHAR2_C4"', + '"INTEGER_C1", "DECIMAL18__3_C2"', '"INTEGER_C1", "VARCHAR2_C4"'] +to_timestamp: ['"DATE_C5"', '"TIMESTAMP_C6"', '"TIMESTAMP_C6", "DECIMAL18__3_C2"', + '"TIMESTAMP_C6", "VARCHAR2_C4"'] +translate: ['"VARCHAR2_C4", "VARCHAR2_C4", "VARCHAR2_C4"'] +trim: ['"VARCHAR2_C4"', '"VARCHAR2_C4", "VARCHAR2_C4"'] +trunc: ['"DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1"', + '"DECIMAL18__3_C2", "INTEGER_C1"'] +truncate: ['"DOUBLE_PRECISION_C0"', '"DECIMAL18__3_C2"', '"INTEGER_C1", "INTEGER_C1"', + '"DECIMAL18__3_C2", "INTEGER_C1"'] +ucase: ['"VARCHAR2_C4"'] +unicode: ['"VARCHAR2_C4"'] +unicodechr: ['"DOUBLE_PRECISION_C0"', '"INTEGER_C1"', '"DECIMAL18__3_C2"', '"BOOLEAN_C3"'] +upper: ['"VARCHAR2_C4"'] +user: [''] +week: ['"DATE_C5"', '"TIMESTAMP_C6"'] +year: ['"DATE_C5"', '"TIMESTAMP_C6"'] +years_between: ['"DATE_C5", "DATE_C5"', '"DATE_C5", "TIMESTAMP_C6"', '"TIMESTAMP_C6", + "DATE_C5"', '"TIMESTAMP_C6", "TIMESTAMP_C6"'] diff --git a/src/test/resources/logging.properties b/src/test/resources/logging.properties new file mode 100644 index 0000000..8c97abe --- /dev/null +++ b/src/test/resources/logging.properties @@ -0,0 +1,6 @@ +handlers=java.util.logging.ConsoleHandler +.level=INFO +java.util.logging.ConsoleHandler.level=ALL +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.SimpleFormatter.format=%1$tF %1$tT.%1$tL [%4$-7s] %5$s %n +com.exasol.level=ALL diff --git a/versionsMavenPluginRules.xml b/versionsMavenPluginRules.xml new file mode 100644 index 0000000..35bd03d --- /dev/null +++ b/versionsMavenPluginRules.xml @@ -0,0 +1,18 @@ + + + + + (?i).*Alpha(?:-?[\d.]+)? + (?i).*a(?:-?[\d.]+)? + (?i).*Beta(?:-?[\d.]+)? + (?i).*-B(?:-?[\d.]+)? + (?i).*-b(?:-?[\d.]+)? + (?i).*RC(?:-?[\d.]+)? + (?i).*CR(?:-?[\d.]+)? + (?i).*M(?:-?[\d.]+)? + + + + \ No newline at end of file From 86784fdf96fc1e0447e8ba944e48cd88a6e72078 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 11 Jul 2024 08:33:23 -0400 Subject: [PATCH 02/64] Add testsetup Added comment Schema must be uppercase for snowflake --- .../snowflake/SnowflakeSqlDialect.java | 3 +- .../snowflake/SnowflakeSqlDialectIT.java | 6 +- ...lakeVirtualSchemaIntegrationTestSetup.java | 257 ++++++++++++++++++ 3 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java index b69d138..7c2574c 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java @@ -162,7 +162,8 @@ public String applyQuote(String identifier) { return super.quoteIdentifierWithDoubleQuotes(identifier); } - + //Changing this to true fixes java.sql.SQLException: ETL-5402: JDBC-Client-Error: Failed to initialize Query: Cannot perform SELECT. This session does not have a current database. Call 'USE DATABASE', or use a qualified name. + //By using database/catalog name as a prefix. @Override public boolean requiresCatalogQualifiedTableNames(final SqlGenerationContext context) { return true; diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index acf81fe..cf6ebf2 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -32,7 +32,7 @@ class SnowflakeSqlDialectIT { @CloseAfterAll private static final SnowflakeVirtualSchemaIntegrationTestSetup SETUP = new SnowflakeVirtualSchemaIntegrationTestSetup(); private static final String SCHEMA_SNOWFLAKE = "SCHEMA_SNOWFLAKE"; - private static final String SCHEMA_SNOWFLAKE_UPPERCASE_TABLE = "schema_snowflake_upper"; + private static final String SCHEMA_SNOWFLAKE_UPPERCASE_TABLE = "SCHEMA_SNOWFLAKE_UPPER"; private static final String TABLE_SNOWFLAKE_SIMPLE = "table_snowflake_simple"; private static final String TABLE_SNOWFLAKE_MIXED_CASE = "Table_Snowflake_Mixed_Case"; private static final String TABLE_SNOWFLAKE_LOWER_CASE = "table_snowflake_lower_case"; @@ -55,7 +55,7 @@ static void beforeAll() throws SQLException { statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE); statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE); createSnowflakeTestTableSimple(statementSnowflake); - // createSnowflakeTestTableAllDataTypes(statementSnowflake); + createSnowflakeTestTableAllDataTypes(statementSnowflake); // createSnowflakeTestTableMixedCase(statementSnowflake); // createSnowflakeTestTableLowerCase(statementSnowflake); // createTestTablesForJoinTests(SCHEMA_SNOWFLAKE); @@ -93,7 +93,7 @@ private static void createSnowflakeTestTableAllDataTypes(final Statement stateme + "myDate DATE, " // + "myDouble DOUBLE PRECISION, " // + "myInet INET, " // - + "myInteger INTEGER, " // + + "myInteger NUMBER(36,0), " // + "myInterval INTERVAL, " // + "myJson JSON, " // + "myJsonB JSONB, " // diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java new file mode 100644 index 0000000..1af2b87 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -0,0 +1,257 @@ +package com.exasol.adapter.dialects.snowflake; + +import static com.exasol.dbbuilder.dialects.exasol.AdapterScript.Language.JAVA; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.*; +import java.util.*; +import java.util.concurrent.TimeoutException; + +import com.exasol.bucketfs.Bucket; +import com.exasol.bucketfs.BucketAccessException; +import com.exasol.containers.ExasolContainer; +import com.exasol.containers.ExasolService; +import com.exasol.dbbuilder.dialects.exasol.*; +import com.exasol.drivers.JdbcDriver; +import com.exasol.errorreporting.ExaError; +import com.exasol.udfdebugging.UdfTestSetup; +import com.github.dockerjava.api.model.ContainerNetwork; + +/** + * This class contains the common integration test setup for all Snowflake virtual schemas. + */ +public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { + private static final String VIRTUAL_SCHEMAS_JAR_NAME_AND_VERSION = "virtual-schema-dist-12.0.0-snowflake-0.1.0.jar"; + private static final Path PATH_TO_VIRTUAL_SCHEMAS_JAR = Path.of("target", VIRTUAL_SCHEMAS_JAR_NAME_AND_VERSION); + private static final String SCHEMA_EXASOL = "SCHEMA_EXASOL"; + private static final String ADAPTER_SCRIPT_EXASOL = "ADAPTER_SCRIPT_EXASOL"; + private static final String EXASOL_DOCKER_IMAGE_REFERENCE = "8.24.0"; + private static final String SNOWFLAKE_CONTAINER_NAME = "localstack/snowflake:14.2"; + + private static final String JDBC_DRIVER_NAME = "snowflake-jdbc.jar"; + private static final Path JDBC_DRIVER_PATH = Path.of("target/snowflake-driver/" + JDBC_DRIVER_NAME); + + private static final int SNOWFLAKE_PORT = 5432; + private static final String USERNAME_FILE = "username.txt"; + private static final String PASSWORD_FILE = "password.txt"; + private static final String ACCOUNTNAME_FILE = "accountname.txt"; + private final Statement snowflakeStatement; + // private final LocalStackContainer snowflakeContainer = new + // LocalStackContainer(DockerImageName.parse("localstack/snowflake")); + private final ExasolContainer> exasolContainer = new ExasolContainer<>( + EXASOL_DOCKER_IMAGE_REFERENCE).withRequiredServices(ExasolService.BUCKETFS, ExasolService.UDF) + .withReuse(true); + private final Connection exasolConnection; + private final Statement exasolStatement; + private final AdapterScript adapterScript; + private final ConnectionDefinition connectionDefinition; + private final ExasolObjectFactory exasolFactory; + // private final SnowflakeObjectFactory snowflakeFactory; + private final Connection snowflakeConnection; + private int virtualSchemaCounter = 0; + private String userName; + private String password; + private String accountName; + + SnowflakeVirtualSchemaIntegrationTestSetup() { + try { + this.exasolContainer.start(); + // TODO add localstack support + cleanup + // this.snowflakeContainer.start(); + final Bucket bucket = this.exasolContainer.getDefaultBucket(); + uploadDriverToBucket(this.exasolContainer); + uploadVsJarToBucket(bucket); + this.exasolConnection = this.exasolContainer.createConnection(""); + this.exasolStatement = this.exasolConnection.createStatement(); + getTestCredentials(); + // TODO add localstack support + cleanup + this.snowflakeConnection = getSnowflakeConnection(userName, password, accountName);// this.snowflakeContainer.createConnection(""); + this.snowflakeStatement = snowflakeConnection.createStatement();// this.snowflakeConnection.createStatement(); + + final String hostIpAddress = getTestHostIpFromInsideExasol(); + assert (hostIpAddress != null); + final UdfTestSetup udfTestSetup = new UdfTestSetup(hostIpAddress, this.exasolContainer.getDefaultBucket(), + this.exasolConnection); + this.exasolFactory = new ExasolObjectFactory(this.exasolContainer.createConnection(""), + ExasolObjectConfiguration.builder().withJvmOptions(udfTestSetup.getJvmOptions()).build()); + final ExasolSchema exasolSchema = this.exasolFactory.createSchema(SCHEMA_EXASOL); + // this.snowflakeFactory = new SnowflakeObjectFactory(this.snowflakeConnection); + this.adapterScript = createAdapterScript(exasolSchema); + // TODO add localstack support + cleanup + final String connectionString = getSnowflakeConnectionString(accountName); + // TODO add localstack support + cleanup + connectionDefinition = getSnowflakeConnectionDefinition(connectionString, userName, password); + } catch (final SQLException | BucketAccessException | TimeoutException exception) { + throw new IllegalStateException("Failed to created snowflake test setup.", exception); + } catch (final InterruptedException exception) { + Thread.currentThread().interrupt(); + throw new IllegalStateException("Thread was interrupted"); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + // TODO add localstack support + cleanup + private ConnectionDefinition getSnowflakeConnectionDefinition(final String connectionString, final String username, + final String password) { + final ConnectionDefinition connectionDefinition; + connectionDefinition = this.exasolFactory.createConnectionDefinition("SNOWFLAKE_CONNECTION", connectionString, + username, password); + return connectionDefinition; + } + + // TODO add localstack support + cleanup + private String getSnowflakeConnectionString(final String accountname) { + // final String connectionString = "jdbc:snowflake://" + this.exasolContainer.getHostIp() + ":" + // + this.snowflakeContainer.getMappedPort(SNOWFLAKE_PORT) + "/" + // + this.snowflakeContainer.getDatabaseName(); + final String connectionString = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; + return connectionString; + } + + // TODO add localstack support + cleanup + private static Connection getSnowflakeConnection(final String username, final String password, + final String accountname) throws SQLException { + // TODO refactor this whole thing and remove secrets + add localstack support + try { + Class.forName("net.snowflake.client.jdbc.SnowflakeDriver"); + } catch (final ClassNotFoundException ex) { + System.err.println("Driver not found"); + } + + // build connection properties + final Properties properties = new Properties(); + properties.put("user", username); // replace "" with your username + properties.put("password", password); // replace "" with your password + properties.put("account", accountname); // replace "" with your account name + properties.put("db", "TESTDB"); // replace "" with target database name + properties.put("schema", "TESTSCHEMA"); // replace "" with target schema name + // properties.put("tracing", "on"); + + // create a new connection + String connectStr = System.getenv("SF_JDBC_CONNECT_STRING"); + // use the default connection string if it is not set in environment + if (connectStr == null) { + connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your + // account name + } + return DriverManager.getConnection(connectStr, properties); + } + + private void getTestCredentials() throws IOException { + if (!Files.exists(Path.of(USERNAME_FILE))) { + throw new IllegalStateException("Could not find " + USERNAME_FILE + + ". Please create a Snowflake account, get the username and store it in this project in " + + USERNAME_FILE + "."); + } + if (!Files.exists(Path.of(PASSWORD_FILE))) { + throw new IllegalStateException("Could not find " + PASSWORD_FILE + + ". Please create a Snowflake account, get the password and store it in this project in " + + PASSWORD_FILE + "."); + } + if (!Files.exists(Path.of(ACCOUNTNAME_FILE))) { + throw new IllegalStateException("Could not find " + ACCOUNTNAME_FILE + + ". Please create a Snowflake account, get the accountName (part of the specific login url you get when creating the account) and store it in this project in " + + ACCOUNTNAME_FILE + "."); + } + + this.userName = Files.readString(Path.of(USERNAME_FILE)).replace("\n", "").replace("\r", ""); + this.password = Files.readString(Path.of(PASSWORD_FILE)).replace("\n", "").replace("\r", ""); + this.accountName = Files.readString(Path.of(ACCOUNTNAME_FILE)).replace("\n", "").replace("\r", ""); + } + + private static void uploadDriverToBucket(final ExasolContainer> container) + throws InterruptedException, TimeoutException, BucketAccessException { + try { + container.getDriverManager().install( // + JdbcDriver.builder("SNOWFLAKE_JDBC_DRIVER") // + .enableSecurityManager(false) // + .mainClass("net.snowflake.client.jdbc.SnowflakeDriver") // + .prefix("jdbc:snowflake:") // + .sourceFile(JDBC_DRIVER_PATH) // + .build()); + + } catch (final Exception exception) { + throw new IllegalStateException( + ExaError.messageBuilder("F-VSSF-8") + .message("An error occurred while uploading the jdbc driver to the bucket.") + .mitigation("Make sure the {{JDBC_DRIVER_PATH}} file exists.") + .parameter("JDBC_DRIVER_PATH", JDBC_DRIVER_PATH) + .mitigation("You can generate it by executing the integration test with maven.").toString(), + exception); + } + } + + private static void uploadVsJarToBucket(final Bucket bucket) { + try { + bucket.uploadFile(PATH_TO_VIRTUAL_SCHEMAS_JAR, VIRTUAL_SCHEMAS_JAR_NAME_AND_VERSION); + } catch (FileNotFoundException | BucketAccessException | TimeoutException exception) { + throw new IllegalStateException("Failed to upload jar to bucket " + bucket, exception); + } + } + + private AdapterScript createAdapterScript(final ExasolSchema schema) { + final String content = "%scriptclass com.exasol.adapter.RequestDispatcher;\n" // + + "%jar /buckets/bfsdefault/default/" + VIRTUAL_SCHEMAS_JAR_NAME_AND_VERSION + ";\n"; + return schema.createAdapterScript(ADAPTER_SCRIPT_EXASOL, JAVA, content); + } + + // public SnowflakeObjectFactory getSnowflakeFactory() { + // return this.snowflakeFactory; + // } + + public Statement getSnowflakeStatement() { + return this.snowflakeStatement; + } + + public Statement getExasolStatement() { + return this.exasolStatement; + } + + public ExasolContainer> getExasolContainer() { + return this.exasolContainer; + } + + public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, + final Map additionalProperties) { + // TODO add localstack support + cleanup + final Map properties = new HashMap<>(Map.of("CATALOG_NAME", "TESTDB", // + "SCHEMA_NAME", forSnowflakeSchema)); // + // "ACCOUNT_NAME", "bfcxnza-jg09523")); + properties.putAll(additionalProperties); + return this.exasolFactory + .createVirtualSchemaBuilder("SNOWFLAKE_VIRTUAL_SCHEMA_" + (this.virtualSchemaCounter++)) + .adapterScript(this.adapterScript).connectionDefinition(this.connectionDefinition) + .properties(properties).build(); + } + + public ExasolObjectFactory getExasolFactory() { + return this.exasolFactory; + } + + @Override + public void close() { + try { + this.exasolStatement.close(); + this.exasolConnection.close(); + this.snowflakeStatement.close(); + this.snowflakeConnection.close(); + this.exasolContainer.stop(); + // TODO add localstack support + cleanup + // this.snowflakeContainer.stop(); + } catch (final SQLException exception) { + throw new IllegalStateException("Failed to stop test setup.", exception); + } + } + + private String getTestHostIpFromInsideExasol() { + final Map networks = this.exasolContainer.getContainerInfo().getNetworkSettings() + .getNetworks(); + if (networks.size() == 0) { + return null; + } + return networks.values().iterator().next().getGateway(); + } +} From 08dbd6922c680b127a736ee83483ba1a85010eb7 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 11 Jul 2024 08:33:37 -0400 Subject: [PATCH 03/64] Changes to gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index b1e8103..807c1e4 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,7 @@ venv/ /.apt_generated_tests/ *.flattened-pom.xml /bin/ + +username.txt +password.txt +accountname.txt \ No newline at end of file From a483babc27fc468eaaac3cc1402c919e2c9ebf65 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Wed, 7 Aug 2024 08:45:19 -0400 Subject: [PATCH 04/64] - cleaned up integration test class somewhat - fixed "no database context issue" on new snowflake test account by attempting to create new database every time making the tests more resilient --- .../snowflake/SnowflakeSqlDialectIT.java | 363 ++++-------------- 1 file changed, 82 insertions(+), 281 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index cf6ebf2..9c5d858 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -2,11 +2,7 @@ import static com.exasol.matcher.ResultSetMatcher.matchesResultSet; import static com.exasol.matcher.ResultSetStructureMatcher.table; -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertThrows; import java.sql.*; import java.text.ParseException; @@ -21,7 +17,6 @@ import com.exasol.closeafterall.CloseAfterAll; import com.exasol.closeafterall.CloseAfterAllExtension; -import com.exasol.dbbuilder.dialects.DatabaseObjectException; import com.exasol.dbbuilder.dialects.Schema; import com.exasol.dbbuilder.dialects.exasol.VirtualSchema; import com.exasol.matcher.TypeMatchMode; @@ -34,8 +29,6 @@ class SnowflakeSqlDialectIT { private static final String SCHEMA_SNOWFLAKE = "SCHEMA_SNOWFLAKE"; private static final String SCHEMA_SNOWFLAKE_UPPERCASE_TABLE = "SCHEMA_SNOWFLAKE_UPPER"; private static final String TABLE_SNOWFLAKE_SIMPLE = "table_snowflake_simple"; - private static final String TABLE_SNOWFLAKE_MIXED_CASE = "Table_Snowflake_Mixed_Case"; - private static final String TABLE_SNOWFLAKE_LOWER_CASE = "table_snowflake_lower_case"; private static final String TABLE_SNOWFLAKE_ALL_DATA_TYPES = "table_snowflake_all_data_types"; private static Schema exasolSchema; private static VirtualSchema virtualSchemaSnowflake; @@ -50,23 +43,27 @@ class SnowflakeSqlDialectIT { @BeforeAll static void beforeAll() throws SQLException { final Statement statementSnowflake = SETUP.getSnowflakeStatement(); - statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE + " CASCADE"); - statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + " CASCADE"); + try { + statementSnowflake.execute("CREATE DATABASE " + "TESTDB"); + } catch (final Exception e) { + + } + try { + statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE + " CASCADE"); + statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + " CASCADE"); + } catch (final Exception e) { + + } statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE); statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE); createSnowflakeTestTableSimple(statementSnowflake); createSnowflakeTestTableAllDataTypes(statementSnowflake); - // createSnowflakeTestTableMixedCase(statementSnowflake); - // createSnowflakeTestTableLowerCase(statementSnowflake); - // createTestTablesForJoinTests(SCHEMA_SNOWFLAKE); + createTestTablesForJoinTests(SCHEMA_SNOWFLAKE); statementExasol = SETUP.getExasolStatement(); virtualSchemaSnowflake = SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE, Map.of()); - // virtualSchemaSnowflakeUppercaseTable = SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE_UPPERCASE_TABLE, - // Map.of("IGNORE_ERRORS", "SNOWFLAKE_UPPERCASE_TABLES")); - // virtualSchemaSnowflakePreserveOriginalCase = SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE_UPPERCASE_TABLE, - // Map.of("SNOWFLAKE_IDENTIFIER_MAPPING", "PRESERVE_ORIGINAL_CASE")); - // QUALIFIED_TABLE_JOIN_NAME_1 = virtualSchemaSnowflake.getName() + "." + TABLE_JOIN_1; - // QUALIFIED_TABLE_JOIN_NAME_2 = virtualSchemaSnowflake.getName() + "." + TABLE_JOIN_2; + + QUALIFIED_TABLE_JOIN_NAME_1 = virtualSchemaSnowflake.getName() + "." + TABLE_JOIN_1; + QUALIFIED_TABLE_JOIN_NAME_2 = virtualSchemaSnowflake.getName() + "." + TABLE_JOIN_2; exasolSchema = SETUP.getExasolFactory().createSchema("EXASOL_TEST_SCHEMA"); } @@ -76,104 +73,102 @@ private static void createSnowflakeTestTableSimple(final Statement statementSnow statementSnowflake.execute("INSERT INTO " + qualifiedTableName + " VALUES (1)"); } + // https://docs.snowflake.com/en/sql-reference/intro-summary-data-types private static void createSnowflakeTestTableAllDataTypes(final Statement statementSnowflake) throws SQLException { final String qualifiedTableName = SCHEMA_SNOWFLAKE + "." + TABLE_SNOWFLAKE_ALL_DATA_TYPES; - statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (" // + final String createAllDatatypesTableStatement = "CREATE TABLE " + qualifiedTableName // + + " (" // + "myBigint BIGINT, " // - + "myBigserial BIGSERIAL, " // - + "myBit BIT, " // - + "myBitVar BIT, " // + // + "myBigserial BIGSERIAL, " //does not exist in SNOWFLAKE + // + "myBit BIT, " //BIT does not exist in SNOWFLAKE, use INT instead + // + "myBitVar BIT, " //BIT does not exist in SNOWFLAKE, use INT instead + "myBoolean BOOLEAN, " // - + "myBox BOX, " // - + "myBytea BYTEA, " // + // + "myBox BOX, " // + // + "myBytea BYTEA, " // + "myCharacter CHARACTER(1000), " // + "myCharacterVar CHARACTER, " // - + "myCidr CIDR, " // - + "myCircle CIRCLE, " // + // + "myCidr CIDR, " // + // + "myCircle CIRCLE, " // + "myDate DATE, " // + "myDouble DOUBLE PRECISION, " // - + "myInet INET, " // - + "myInteger NUMBER(36,0), " // - + "myInterval INTERVAL, " // - + "myJson JSON, " // - + "myJsonB JSONB, " // - + "myLine LINE, " // - + "myLseg LSEG, " // - + "myMacAddr MACADDR, " // - + "myMoney MONEY, " // - + "myNumeric NUMERIC(36, 10), " // - + "myPath PATH, " // - + "myPoint POINT, " // - + "myPolygon POLYGON, " // + // + "myInet INET, " // + + "myInteger NUMBER(36,0), " // INT (EGER) has (38,0) precision and scale in snowflake, Exasol has + // (36,0) + // as a max. The integer datatype causes problems with the EXALOADER. + // TODO: demonstrate this to TB + // + "myInterval INTERVAL, " // + // + "myJson JSON, " // + // + "myJsonB JSONB, " // + // + "myLine LINE, " // + // + "myLseg LSEG, " // + // + "myMacAddr MACADDR, " // + // + "myMoney MONEY, " // + + "myNumeric NUMERIC(36, 10), " // same as NUMBER IN snowflake + // + "myPath PATH, " // + // + "myPoint POINT, " // + // + "myPolygon POLYGON, " // + "myReal REAL, " // + "mySmallint SMALLINT, " // + "myText TEXT, " // + "myTime TIME, " // - + "myTimeWithTimeZone TIME WITH TIME ZONE, " // + // + "myTimeWithTimeZone TIME WITH TIME ZONE, " //DOES NOT EXIST IN SNOWFLAKE + "myTimestamp TIMESTAMP, " // - + "myTimestampWithTimeZone TIMESTAMP WITH TIME ZONE, " // - + "myTsquery TSQUERY, " // - + "myTsvector TSVECTOR, " // - + "myUuid UUID, " // - + "myXml XML " // - + ")"); - statementSnowflake.execute("INSERT INTO " + qualifiedTableName + " VALUES (" // + + "myTimestampWithTimeZone TIMESTAMP_TZ " // TIMESTAMP WITH TIME ZONE + // + "myTsquery TSQUERY, " // + // + "myTsvector VECTOR, " // + // + "myUuid UUID, " //SUBTYPE OF STRING IN SNOWFLAKE + // + "myXml XML " //DOES NOT EXIST IN SNOWFLAKE + + ")"; + statementSnowflake.execute(createAllDatatypesTableStatement); + final String fillAllDatabaseTypesStatement = ("INSERT INTO " + qualifiedTableName + " VALUES (" // + "10000000000, " // myBigint - + "nextval('" + qualifiedTableName + "_myBigserial_seq'::regclass), " // myBigserial - + "B'1', " // myBit - + "B'0', " // myBitVar + // + "nextval('" + qualifiedTableName + "_myBigserial_seq'::regclass), " // myBigserial + // + "B'1', " // myBit + // + "B'0', " // myBitVar + "false, " // myBoolean - + "'( ( 1 , 8 ) , ( 4 , 16 ) )', " // myBox - + "E'\\\\000'::bytea, " // myBytea + // + "'( ( 1 , 8 ) , ( 4 , 16 ) )', " // myBox + // + "E'\\\\000'::bytea, " // myBytea + "'hajksdf', " // myCharacter - + "'hjkdhjgfh', " // myCharacterVar - + "'192.168.100.128/25'::cidr, " // myCidr - + "'( ( 1 , 5 ) , 3 )'::circle, " // myCircle + + "'h', " // myCharacterVar + // + "'192.168.100.128/25'::cidr, " // myCidr + // + "'( ( 1 , 5 ) , 3 )'::circle, " // myCircle + "'2010-01-01', " // myDate + "192189234.1723854, " // myDouble - + "'192.168.100.128'::inet, " // myInet + // + "'192.168.100.128'::inet, " // myInet + "7189234, " // myInteger - + "INTERVAL '1' YEAR, " // myInterval - + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::json, " // myJson - + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::jsonb, " // myJsonB - + "'{ 1, 2, 3 }'::line, " // myLine - + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::lseg, " // myLseg - + "'08:00:2b:01:02:03'::macaddr, " // myMacAddr - + "100.01, " // myMoney + // + "INTERVAL '1' YEAR, " // myInterval + // + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::json, " // myJson + // + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::jsonb, " // myJsonB + // + "'{ 1, 2, 3 }'::line, " // myLine + // + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::lseg, " // myLseg + // + "'08:00:2b:01:02:03'::macaddr, " // myMacAddr + // + "100.01, " // myMoney + "24.23, " // myNumeric - + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::path, " // myPath - + "'( 1 , 3 )'::point, " // myPoint - + "'( ( 1 , 2 ) , (2,4),(3,7) )'::polygon, " // myPolygon + // + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::path, " // myPath + // + "'( 1 , 3 )'::point, " // myPoint + // + "'( ( 1 , 2 ) , (2,4),(3,7) )'::polygon, " // myPolygon + "10.12, " // myReal + "100, " // mySmallint + "'This cat is super cute', " // myText + "'11:11:11', " // myTime - + "'11:11:11 +01:00', " // myTimeWithTimeZone + // + "'11:11:11 +01:00', " // myTimeWithTimeZone + "'2010-01-01 11:11:11', " // myTimestamp - + "'2010-01-01 11:11:11 +01:00', " // myTimestampwithtimezone - + "'fat & rat'::tsquery, " // myTsquery - + "to_tsvector('english', 'The Fat Rats'), " // myTsvector - + "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, " // myUuid - + "XMLPARSE (DOCUMENT 'Manual...') " // myXml + + "'2010-01-01 11:11:11 +01:00' " // myTimestampwithtimezone + // + "'fat & rat'::tsquery, " // myTsquery + // + "VECTOR('english', 'The Fat Rats'), " // myTsvector + // + "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, " // myUuid + // + "XMLPARSE (DOCUMENT 'Manual...') " // myXml + ")"); - } - - private static void createSnowflakeTestTableMixedCase(final Statement statementSnowflake) throws SQLException { - final String qualifiedTableName = SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + ".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\""; - statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (x INT, \"Y\" INT)"); - } - - private static void createSnowflakeTestTableLowerCase(final Statement statementSnowflake) throws SQLException { - final String qualifiedTableName = SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + "." + TABLE_SNOWFLAKE_LOWER_CASE; - statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (x INT, y INT)"); + statementSnowflake.execute(fillAllDatabaseTypesStatement); } private static void createTestTablesForJoinTests(final String schemaName) throws SQLException { final Statement statement = SETUP.getSnowflakeStatement(); - statement.execute("CREATE TABLE " + schemaName + "." + TABLE_JOIN_1 + "(x INT, y VARCHAR(100))"); + statement.execute("CREATE TABLE " + schemaName + "." + TABLE_JOIN_1 + "(x NUMBER(36,0), y VARCHAR(100))"); statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_1 + " VALUES (1,'aaa')"); statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_1 + " VALUES (2,'bbb')"); - statement.execute("CREATE TABLE " + schemaName + "." + TABLE_JOIN_2 + "(x INT, y VARCHAR(100))"); + statement.execute("CREATE TABLE " + schemaName + "." + TABLE_JOIN_2 + "(x NUMBER(36,0), y VARCHAR(100))"); statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_2 + " VALUES (2,'bbb')"); statement.execute("INSERT INTO " + schemaName + "." + TABLE_JOIN_2 + " VALUES (3,'ccc')"); } @@ -191,7 +186,8 @@ void testInnerJoin() throws SQLException { + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x"; final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // List.of("2,'bbb', 2,'bbb'")); - assertThat(getActualResultSet(query), matchesResultSet(expected)); + final ResultSet actualResultSet = getActualResultSet(query); + assertThat(actualResultSet, matchesResultSet(expected)); } @Test @@ -302,123 +298,16 @@ void testCountAll() throws SQLException { assertThat(actualResultSet, table("BIGINT").row(1L).matches()); } - @Test - void testCreateSchemaWithUpperCaseTablesThrowsException() { - final Exception exception = assertThrows(DatabaseObjectException.class, - () -> SETUP.createVirtualSchema(SCHEMA_SNOWFLAKE_UPPERCASE_TABLE, Map.of())); - assertThat(exception.getMessage(), containsString("Failed to write to object")); - } - - @Test - void testQueryUpperCaseTableQuotedThrowsException() { - final String selectStatement = "SELECT x FROM " + virtualSchemaSnowflakeUppercaseTable.getName() + ".\"" - + TABLE_SNOWFLAKE_MIXED_CASE + "\""; - final Exception exception = assertThrows(SQLException.class, () -> statementExasol.execute(selectStatement)); - assertThat(exception.getMessage(), containsString(".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\" not found")); - } - - @Test - void testQueryUpperCaseTableThrowsException() { - final Exception exception = assertThrows(SQLException.class, () -> statementExasol.execute( - "SELECT x FROM " + virtualSchemaSnowflakeUppercaseTable.getName() + "." + TABLE_SNOWFLAKE_MIXED_CASE)); - assertThat(exception.getMessage(), containsString("object " + virtualSchemaSnowflakeUppercaseTable.getName() - + "." + TABLE_SNOWFLAKE_MIXED_CASE.toUpperCase() + " not found")); - } - - @Test - void testQueryLowerCaseTable() throws SQLException { - final ResultSet result = statementExasol.executeQuery( - "SELECT x FROM " + virtualSchemaSnowflakeUppercaseTable.getName() + "." + TABLE_SNOWFLAKE_LOWER_CASE); - assertThat(result.next(), equalTo(false)); - } - - @Test - void testUnsetIgnoreUpperCaseTablesAndRefreshThrowsException() throws SQLException { - statementExasol.execute( - "ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + " set ignore_errors=''"); - statementExasol.execute("ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() - + " set SNOWFLAKE_IDENTIFIER_MAPPING = 'CONVERT_TO_UPPER'"); - final Exception exception = assertThrows(SQLException.class, () -> statementExasol - .execute("ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() + " REFRESH")); - assertThat(exception.getMessage(), containsString("E-VSSF-6: Table '" + TABLE_SNOWFLAKE_MIXED_CASE - + "' cannot be used in virtual schema. Set property 'IGNORE_ERRORS' to 'SNOWFLAKE_UPPERCASE_TABLES' to enforce schema creation.")); - } - - @Test - void testSetIgnoreUpperCaseTablesAndRefresh() throws SQLException { - statementExasol.execute("ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() - + " set ignore_errors='SNOWFLAKE_UPPERCASE_TABLES'"); - final String refresh_schema_query = "ALTER VIRTUAL SCHEMA " + virtualSchemaSnowflakeUppercaseTable.getName() - + " REFRESH"; - assertDoesNotThrow(() -> statementExasol.execute(refresh_schema_query)); - } - - @Test - void testPreserveCaseQueryLowerCaseTableThrowsException() { - final SQLException exception = assertThrows(SQLException.class, - () -> statementExasol.executeQuery("SELECT x FROM " - + virtualSchemaSnowflakePreserveOriginalCase.getName() + "." + TABLE_SNOWFLAKE_LOWER_CASE)); - assertThat(exception.getMessage(), - containsString("object " + virtualSchemaSnowflakePreserveOriginalCase.getName() + "." - + TABLE_SNOWFLAKE_LOWER_CASE.toUpperCase() + " not found")); - } - - @Test - void testPreserveCaseQueryLowerCaseTableWithQuotes() throws SQLException { - final ResultSet result = statementExasol.executeQuery("SELECT \"x\" FROM " - + virtualSchemaSnowflakePreserveOriginalCase.getName() + ".\"" + TABLE_SNOWFLAKE_LOWER_CASE + "\""); - assertThat(result.next(), equalTo(false)); - } - - @Test - void testPreserveCaseQueryUpperCaseTableWithQuotes() throws SQLException { - final ResultSet result = statementExasol.executeQuery("SELECT \"Y\" FROM " - + virtualSchemaSnowflakePreserveOriginalCase.getName() + ".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\""); - assertThat(result.next(), equalTo(false)); - } - @Test void testDatatypeBigint() throws SQLException { assertSingleValue("myBigint", "DECIMAL(19,0)", "10000000000"); } - @Test - void testPreserveCaseQueryUpperCaseTableWithQuotesLowerCaseColumn() throws SQLException { - final ResultSet result = statementExasol.executeQuery("SELECT \"x\" FROM " - + virtualSchemaSnowflakePreserveOriginalCase.getName() + ".\"" + TABLE_SNOWFLAKE_MIXED_CASE + "\""); - assertThat(result.next(), equalTo(false)); - } - - @Test - void testDatatypeBigSerial() throws SQLException { - assertSingleValue("myBigserial", "DECIMAL(19,0)", "1"); - } - - @Test - void testDatatypeBit() throws SQLException { - assertSingleValue("myBit", "BOOLEAN", true); - } - - @Test - void testDatatypeBitVar() throws SQLException { - assertSingleValue("myBitvar", "VARCHAR(5) UTF8", "0"); - } - @Test void testDatatypeBoolean() throws SQLException { assertSingleValue("myBoolean", "BOOLEAN", false); } - @Test - void testDatatypeBox() throws SQLException { - assertSingleValue("myBox", "VARCHAR(2000000) UTF8", "(4,16),(1,8)"); - } - - @Test - void testDatatypeBytea() throws SQLException { - assertSingleValue("myBytea", "VARCHAR(2000000) UTF8", "bytea NOT SUPPORTED"); - } - @Test void testDatatypeCharacter() throws SQLException { final String empty = " "; @@ -428,17 +317,7 @@ void testDatatypeCharacter() throws SQLException { @Test void testDatatypeCharacterVar() throws SQLException { - assertSingleValue("myCharactervar", "VARCHAR(1000) UTF8", "hjkdhjgfh"); - } - - @Test - void testDatatypeCidr() throws SQLException { - assertSingleValue("myCidr", "VARCHAR(2000000) UTF8", "192.168.100.128/25"); - } - - @Test - void testDatatypeCircle() throws SQLException { - assertSingleValue("myCircle", "VARCHAR(2000000) UTF8", "<(1,5),3>"); + assertSingleValue("myCharactervar", "VARCHAR(1000) UTF8", "h"); } @Test @@ -452,73 +331,16 @@ void testDatatypeDouble() throws SQLException { assertSingleValue("myDouble", "DOUBLE", "192189234.1723854"); } - @Test - void testDatatypeInet() throws SQLException { - assertSingleValue("myInet", "VARCHAR(2000000) UTF8", "192.168.100.128/32"); - } - @Test void testDatatypeInteger() throws SQLException { assertSingleValue("myInteger", "DECIMAL(10,0)", "7189234"); } - @Test - void testDatatypeIntervalYM() throws SQLException { - assertSingleValue("myInterval", "VARCHAR(2000000) UTF8", "1 year"); - } - - @Test - void testDatatypeJSON() throws SQLException { - assertSingleValue("myJson", "VARCHAR(2000000) UTF8", - "{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}"); - } - - @Test - void testDatatypeJSONB() throws SQLException { - assertSingleValue("myJsonb", "VARCHAR(2000000) UTF8", - "{\"bar\": \"baz\", \"active\": false, \"balance\": 7.77}"); - } - - @Test - void testDatatypeLine() throws SQLException { - assertSingleValue("myLine", "VARCHAR(2000000) UTF8", "{1,2,3}"); - } - - @Test - void testDatatypeLSeg() throws SQLException { - assertSingleValue("myLseg", "VARCHAR(2000000) UTF8", "[(1,2),(3,4)]"); - } - - @Test - void testDatatypeMACAddr() throws SQLException { - assertSingleValue("myMacaddr", "VARCHAR(2000000) UTF8", "08:00:2b:01:02:03"); - } - - @Test - void testDatatypeMoney() throws SQLException { - assertSingleValue("myMoney", "DOUBLE", 100.01); - } - @Test void testDatatypeNumeric() throws SQLException { assertSingleValue("myNumeric", "VARCHAR(2000000) UTF8", 24.2300000000); } - @Test - void testDatatypePath() throws SQLException { - assertSingleValue("myPath", "VARCHAR(2000000) UTF8", "[(1,2),(3,4)]"); - } - - @Test - void testDatatypePoint() throws SQLException { - assertSingleValue("myPoint", "VARCHAR(2000000) UTF8", "(1,3)"); - } - - @Test - void testDatatypePolygon() throws SQLException { - assertSingleValue("myPolygon", "VARCHAR(2000000) UTF8", "((1,2),(2,4),(3,7))"); - } - @Test void testDatatypeReal() throws SQLException { assertSingleValue("myReal", "DOUBLE", 10.12); @@ -558,27 +380,6 @@ void testDatatypeTimestampWithTimezone() throws SQLException, ParseException { assertSingleValue("myTimestampwithtimezone", "TIMESTAMP", expectedDate); } - @Test - void testDatatypeTsQuery() throws SQLException { - assertSingleValue("myTsquery", "VARCHAR(2000000) UTF8", "'fat' & 'rat'"); - } - - @Test - void testDatatypeTsvector() throws SQLException { - assertSingleValue("myTsvector", "VARCHAR(2000000) UTF8", "'fat':2 'rat':3"); - } - - @Test - void testDatatypeUUID() throws SQLException { - assertSingleValue("myUuid", "VARCHAR(2000000) UTF8", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"); - } - - @Test - void testDatatypeXML() throws SQLException { - assertSingleValue("myXml", "VARCHAR(2000000) UTF8", - "Manual..."); - } - private void assertSingleValue(final String columnName, final String expectedColumnType, final Object expectedValue) throws SQLException { final ResultSet actual = statementExasol.executeQuery("SELECT " + columnName + " FROM " From 549e2431868b1d750401ec0bbcb0631aedd99d51 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 13 Aug 2024 06:59:26 -0400 Subject: [PATCH 05/64] Fix expected types for join tests --- .../snowflake/SnowflakeSqlDialectIT.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index 9c5d858..9acebda 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -184,7 +184,8 @@ void testSelectSingleColumn() throws SQLException { void testInnerJoin() throws SQLException { final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a INNER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x"; - final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + final ResultSet expected = getExpectedResultSet( + List.of("x DECIMAL(36,0)", "y VARCHAR(100)", "a DECIMAL(36,0)", "b VARCHAR(100)"), // List.of("2,'bbb', 2,'bbb'")); final ResultSet actualResultSet = getActualResultSet(query); assertThat(actualResultSet, matchesResultSet(expected)); @@ -203,7 +204,8 @@ void testInnerJoinWithProjection() throws SQLException { void testLeftJoin() throws SQLException { final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a LEFT OUTER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x ORDER BY a.x"; - final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + final ResultSet expected = getExpectedResultSet( + List.of("x DECIMAL(36,0)", "y VARCHAR(100)", "a DECIMAL(36,0)", "b VARCHAR(100)"), // List.of("1, 'aaa', null, null", // "2, 'bbb', 2, 'bbb'")); assertThat(getActualResultSet(query), matchesResultSet(expected)); @@ -213,7 +215,8 @@ void testLeftJoin() throws SQLException { void testRightJoin() throws SQLException { final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a RIGHT OUTER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x ORDER BY a.x"; - final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + final ResultSet expected = getExpectedResultSet( + List.of("x DECIMAL(36,0)", "y VARCHAR(100)", "a DECIMAL(36,0)", "b VARCHAR(100)"), // List.of("2, 'bbb', 2, 'bbb'", // "null, null, 3, 'ccc'")); assertThat(getActualResultSet(query), matchesResultSet(expected)); @@ -223,7 +226,8 @@ void testRightJoin() throws SQLException { void testFullOuterJoin() throws SQLException { final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a FULL OUTER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x=b.x ORDER BY a.x"; - final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + final ResultSet expected = getExpectedResultSet( + List.of("x DECIMAL(36,0)", "y VARCHAR(100)", "a DECIMAL(36,0)", "b VARCHAR(100)"), // List.of("1, 'aaa', null, null", // "2, 'bbb', 2, 'bbb'", // "null, null, 3, 'ccc'")); @@ -234,7 +238,8 @@ void testFullOuterJoin() throws SQLException { void testRightJoinWithComplexCondition() throws SQLException { final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a RIGHT OUTER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x||a.y=b.x||b.y ORDER BY a.x"; - final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + final ResultSet expected = getExpectedResultSet( + List.of("x DECIMAL(36,0)", "y VARCHAR(100)", "a DECIMAL(36,0)", "b VARCHAR(100)"), // List.of("2, 'bbb', 2, 'bbb'", // "null, null, 3, 'ccc'")); assertThat(getActualResultSet(query), matchesResultSet(expected)); @@ -244,7 +249,8 @@ void testRightJoinWithComplexCondition() throws SQLException { void testFullOuterJoinWithComplexCondition() throws SQLException { final String query = "SELECT * FROM " + QUALIFIED_TABLE_JOIN_NAME_1 + " a FULL OUTER JOIN " + QUALIFIED_TABLE_JOIN_NAME_2 + " b ON a.x-b.x=0 ORDER BY a.x"; - final ResultSet expected = getExpectedResultSet(List.of("x INT", "y VARCHAR(100)", "a INT", "b VARCHAR(100)"), // + final ResultSet expected = getExpectedResultSet( + List.of("x DECIMAL(36,0)", "y VARCHAR(100)", "a DECIMAL(36,0)", "b VARCHAR(100)"), // List.of("1, 'aaa', null, null", // "2, 'bbb', 2, 'bbb'", // "null, null, 3, 'ccc'")); @@ -361,11 +367,6 @@ void testDatatypeTime() throws SQLException { assertSingleValue("myTime", "VARCHAR(2000000) UTF8", "1970-01-01 11:11:11.0"); } - @Test - void testDatatypeTimeWithTimezone() throws SQLException { - assertSingleValue("myTimeWithTimeZone", "VARCHAR(2000000) UTF8", "1970-01-01 11:11:11.0"); - } - @Test void testDatatypeTimestamp() throws SQLException, ParseException { final Timestamp expectedDate = new Timestamp( From 9cdfd750918c0042c089d8e6fd2f10bb08646c0b Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 06:05:16 -0400 Subject: [PATCH 06/64] CI build: add snowflake service credentials step --- .github/workflows/ci-build.yml | 11 +++++++++++ .project-keeper.yml | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index f13a04c..268fa2b 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -67,6 +67,17 @@ jobs: id: enable-testcontainer-reuse, run: echo 'testcontainers.reuse.enable=true' > "$HOME/.testcontainers.properties" } + - name: Configure Snowflake credentials + id: configure-snowflake-credentials + run: | + echo "$USERNAME" > username.txt + echo "$ACCOUNTNAME" > accountname.txt + echo "$PASSWORD" > password.txt + env: { + USERNAME: '${{ secrets.USERNAME }}', + ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', + PASSWORD: '${{ secrets.PASSWORD }}' + } - name: Run tests and build with Maven id: build-pk-verify run: | diff --git a/.project-keeper.yml b/.project-keeper.yml index 3af4681..06d9890 100644 --- a/.project-keeper.yml +++ b/.project-keeper.yml @@ -13,3 +13,21 @@ build: exasolDbVersions: - "7.1.25" - "8.24.0" + workflows: + - name: ci-build.yml + stepCustomizations: + # Configure Snowflake credentials + - action: INSERT_AFTER + stepId: enable-testcontainer-reuse + content: + name: Configure Snowflake credentials + id: configure-snowflake-credentials + run: | + echo "$USERNAME" > username.txt + echo "$ACCOUNTNAME" > accountname.txt + echo "$PASSWORD" > password.txt + env: { + USERNAME: '${{ secrets.USERNAME }}', + ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', + PASSWORD: '${{ secrets.PASSWORD }}' + } \ No newline at end of file From f89daee3173c7267a106f6630691313b7abfe614 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 06:13:24 -0400 Subject: [PATCH 07/64] make things a bit easier to debug --- .../adapter/dialects/snowflake/SnowflakeSqlDialectIT.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index 9acebda..9dcf1c0 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -383,9 +383,10 @@ void testDatatypeTimestampWithTimezone() throws SQLException, ParseException { private void assertSingleValue(final String columnName, final String expectedColumnType, final Object expectedValue) throws SQLException { - final ResultSet actual = statementExasol.executeQuery("SELECT " + columnName + " FROM " - + virtualSchemaSnowflake.getName() + "." + TABLE_SNOWFLAKE_ALL_DATA_TYPES); - MatcherAssert.assertThat(actual, table().row(expectedValue).matches(TypeMatchMode.NO_JAVA_TYPE_CHECK)); + final String getActualValueQuery = "SELECT " + columnName + " FROM " + virtualSchemaSnowflake.getName() + "." + + TABLE_SNOWFLAKE_ALL_DATA_TYPES; + final ResultSet actualResultSet = statementExasol.executeQuery(getActualValueQuery); + MatcherAssert.assertThat(actualResultSet, table().row(expectedValue).matches(TypeMatchMode.NO_JAVA_TYPE_CHECK)); } // TODO refactor to use table().row().matches() From 879e5d2301be92876523970fc6f826babd18cea9 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 06:25:06 -0400 Subject: [PATCH 08/64] testing CI after branching issues --- .../snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 1af2b87..707cffe 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -58,7 +58,7 @@ public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { SnowflakeVirtualSchemaIntegrationTestSetup() { try { this.exasolContainer.start(); - // TODO add localstack support + cleanup + // TODO add localstack support // this.snowflakeContainer.start(); final Bucket bucket = this.exasolContainer.getDefaultBucket(); uploadDriverToBucket(this.exasolContainer); From fd06366184703733693ef143fd81112f3bc70b56 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 06:37:14 -0400 Subject: [PATCH 09/64] adding required files for PK --- .settings/org.eclipse.jdt.core.prefs | 502 +++++++++++++++++++++++++++ .settings/org.eclipse.jdt.ui.prefs | 205 +++++++++++ .vscode/settings.json | 23 ++ 3 files changed, 730 insertions(+) create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.jdt.ui.prefs create mode 100644 .vscode/settings.json diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..bb40c3f --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,502 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=11 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=11 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=ignore +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.processAnnotations=disabled +org.eclipse.jdt.core.compiler.release=disabled +org.eclipse.jdt.core.compiler.source=11 +org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns=false +org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns=false +org.eclipse.jdt.core.formatter.align_with_spaces=false +org.eclipse.jdt.core.formatter.alignment_for_additive_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant=49 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field=49 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable=49 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method=49 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package=49 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter=0 +org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type=49 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 +org.eclipse.jdt.core.formatter.alignment_for_assertion_message=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 +org.eclipse.jdt.core.formatter.alignment_for_compact_loops=16 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=16 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0 +org.eclipse.jdt.core.formatter.alignment_for_logical_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_module_statements=16 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator=16 +org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_record_components=16 +org.eclipse.jdt.core.formatter.alignment_for_relational_operator=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_shift_operator=0 +org.eclipse.jdt.core.formatter.alignment_for_string_concatenation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 +org.eclipse.jdt.core.formatter.alignment_for_type_annotations=0 +org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0 +org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch=0 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_record_constructor=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_record_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped=true +org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false +org.eclipse.jdt.core.formatter.comment.indent_root_tags=false +org.eclipse.jdt.core.formatter.comment.indent_tag_description=false +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags=do not insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=120 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=2 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=false +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_additive_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_after_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_not_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_relational_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_additive_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case=insert +org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert +org.eclipse.jdt.core.formatter.insert_space_before_logical_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_relational_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_shift_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation=insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_code_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false +org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_method_body_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line=false +org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line=false +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false +org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line=one_line_never +org.eclipse.jdt.core.formatter.lineSplit=120 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines +org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=space +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.text_block_indentation=0 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_additive_operator=true +org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator=true +org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false +org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator=true +org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true +org.eclipse.jdt.core.formatter.wrap_before_logical_operator=true +org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_before_relational_operator=true +org.eclipse.jdt.core.formatter.wrap_before_shift_operator=true +org.eclipse.jdt.core.formatter.wrap_before_string_concatenation=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true +org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..1add06a --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,205 @@ +cleanup.add_default_serial_version_id=true +cleanup.add_generated_serial_version_id=false +cleanup.add_missing_annotations=true +cleanup.add_missing_deprecated_annotations=true +cleanup.add_missing_methods=false +cleanup.add_missing_nls_tags=false +cleanup.add_missing_override_annotations=true +cleanup.add_missing_override_annotations_interface_methods=true +cleanup.add_serial_version_id=false +cleanup.always_use_blocks=true +cleanup.always_use_parentheses_in_expressions=false +cleanup.always_use_this_for_non_static_field_access=true +cleanup.always_use_this_for_non_static_method_access=false +cleanup.convert_functional_interfaces=true +cleanup.convert_to_enhanced_for_loop=true +cleanup.correct_indentation=true +cleanup.format_source_code=true +cleanup.format_source_code_changes_only=false +cleanup.insert_inferred_type_arguments=false +cleanup.make_local_variable_final=true +cleanup.make_parameters_final=true +cleanup.make_private_fields_final=true +cleanup.make_type_abstract_if_missing_method=false +cleanup.make_variable_declarations_final=true +cleanup.never_use_blocks=false +cleanup.never_use_parentheses_in_expressions=true +cleanup.organize_imports=false +cleanup.qualify_static_field_accesses_with_declaring_class=false +cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +cleanup.qualify_static_member_accesses_with_declaring_class=true +cleanup.qualify_static_method_accesses_with_declaring_class=false +cleanup.remove_private_constructors=true +cleanup.remove_redundant_modifiers=false +cleanup.remove_redundant_semicolons=true +cleanup.remove_redundant_type_arguments=true +cleanup.remove_trailing_whitespaces=true +cleanup.remove_trailing_whitespaces_all=true +cleanup.remove_trailing_whitespaces_ignore_empty=false +cleanup.remove_unnecessary_casts=true +cleanup.remove_unnecessary_nls_tags=true +cleanup.remove_unused_imports=true +cleanup.remove_unused_local_variables=false +cleanup.remove_unused_private_fields=true +cleanup.remove_unused_private_members=true +cleanup.remove_unused_private_methods=true +cleanup.remove_unused_private_types=true +cleanup.sort_members=false +cleanup.sort_members_all=false +cleanup.use_anonymous_class_creation=false +cleanup.use_blocks=true +cleanup.use_blocks_only_for_return_and_throw=false +cleanup.use_lambda=true +cleanup.use_parentheses_in_expressions=true +cleanup.use_this_for_non_static_field_access=true +cleanup.use_this_for_non_static_field_access_only_if_necessary=false +cleanup.use_this_for_non_static_method_access=false +cleanup.use_this_for_non_static_method_access_only_if_necessary=true +cleanup_profile=_Exasol +cleanup_settings_version=2 +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Exasol +formatter_settings_version=21 +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.ondemandthreshold=3 +org.eclipse.jdt.ui.staticondemandthreshold=3 +sp_cleanup.add_all=false +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=true +sp_cleanup.always_use_this_for_non_static_field_access=true +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.array_with_curly=false +sp_cleanup.arrays_fill=false +sp_cleanup.bitwise_conditional_expression=false +sp_cleanup.boolean_literal=false +sp_cleanup.boolean_value_rather_than_comparison=false +sp_cleanup.break_loop=false +sp_cleanup.collection_cloning=false +sp_cleanup.comparing_on_criteria=false +sp_cleanup.comparison_statement=false +sp_cleanup.controlflow_merge=false +sp_cleanup.convert_functional_interfaces=true +sp_cleanup.convert_to_enhanced_for_loop=true +sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=false +sp_cleanup.convert_to_switch_expressions=false +sp_cleanup.correct_indentation=true +sp_cleanup.do_while_rather_than_while=false +sp_cleanup.double_negation=false +sp_cleanup.else_if=false +sp_cleanup.embedded_if=false +sp_cleanup.evaluate_nullable=false +sp_cleanup.extract_increment=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.hash=false +sp_cleanup.if_condition=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.instanceof=false +sp_cleanup.instanceof_keyword=false +sp_cleanup.invert_equals=false +sp_cleanup.join=false +sp_cleanup.lazy_logical_operator=false +sp_cleanup.make_local_variable_final=true +sp_cleanup.make_parameters_final=true +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=true +sp_cleanup.map_cloning=false +sp_cleanup.merge_conditional_blocks=false +sp_cleanup.multi_catch=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=false +sp_cleanup.no_string_creation=false +sp_cleanup.no_super=false +sp_cleanup.number_suffix=false +sp_cleanup.objects_equals=false +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false +sp_cleanup.operand_factorization=false +sp_cleanup.organize_imports=true +sp_cleanup.overridden_assignment=false +sp_cleanup.plain_replacement=false +sp_cleanup.precompile_regex=false +sp_cleanup.primitive_comparison=false +sp_cleanup.primitive_parsing=false +sp_cleanup.primitive_rather_than_wrapper=false +sp_cleanup.primitive_serialization=false +sp_cleanup.pull_out_if_from_if_else=false +sp_cleanup.pull_up_assignment=false +sp_cleanup.push_down_negation=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=true +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.reduce_indentation=false +sp_cleanup.redundant_comparator=false +sp_cleanup.redundant_falling_through_block_end=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=false +sp_cleanup.remove_redundant_semicolons=true +sp_cleanup.remove_redundant_type_arguments=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_array_creation=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.return_expression=false +sp_cleanup.simplify_lambda_expression_and_method_ref=false +sp_cleanup.single_used_field=false +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.standard_comparison=false +sp_cleanup.static_inner_class=false +sp_cleanup.strictly_equal_or_different=false +sp_cleanup.stringbuffer_to_stringbuilder=false +sp_cleanup.stringbuilder=false +sp_cleanup.stringbuilder_for_local_vars=false +sp_cleanup.substring=false +sp_cleanup.switch=false +sp_cleanup.system_property=false +sp_cleanup.system_property_boolean=false +sp_cleanup.system_property_file_encoding=false +sp_cleanup.system_property_file_separator=false +sp_cleanup.system_property_line_separator=false +sp_cleanup.system_property_path_separator=false +sp_cleanup.ternary_operator=false +sp_cleanup.try_with_resource=false +sp_cleanup.unlooped_while=false +sp_cleanup.unreachable_block=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_autoboxing=false +sp_cleanup.use_blocks=true +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_directly_map_method=false +sp_cleanup.use_lambda=true +sp_cleanup.use_parentheses_in_expressions=true +sp_cleanup.use_string_is_blank=false +sp_cleanup.use_this_for_non_static_field_access=true +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=false +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_unboxing=false +sp_cleanup.use_var=false +sp_cleanup.useless_continue=false +sp_cleanup.useless_return=false +sp_cleanup.valueof_rather_than_instantiation=false diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a7ae59b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit", + "source.generate.finalModifiers": "explicit", + "source.fixAll": "explicit" + }, + "java.codeGeneration.useBlocks": true, + "java.saveActions.organizeImports": true, + "java.sources.organizeImports.starThreshold": 3, + "java.sources.organizeImports.staticStarThreshold": 3, + "java.test.config": { + "vmArgs": [ + "-Djava.util.logging.config.file=src/test/resources/logging.properties", + "-Dtest.debug='true'", + "-Dcom.exasol.dockerdb.image=8.24.0" + ] + }, + "sonarlint.connectedMode.project": { + "connectionId": "exasol", + "projectKey": "com.exasol:snowflake-virtual-schema" + } +} \ No newline at end of file From 18b52c6785e72323a68a14cfd9a8746e3a7bb388 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 06:38:05 -0400 Subject: [PATCH 10/64] fix version doc vert spacing --- doc/changes/changes_0.1.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 59e0a4b..0400662 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -6,7 +6,8 @@ Code name: First version ## Features / Enhancements -* #1: SomethingSomething #TO DO +* #1: Something Something #TO DO + ## Dependency Updates ### Compile Dependency Updates From a9e9c1ea0dac0ab84bf453e7eb24230587f555a7 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 06:52:21 -0400 Subject: [PATCH 11/64] Added summary --- doc/changes/changes_0.1.0.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 0400662..14546ce 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -4,9 +4,11 @@ Code name: First version ## Summary -## Features / Enhancements +This is the MVP release. -* #1: Something Something #TO DO +## Features + +* #1: Releasing the MVP ## Dependency Updates From 39d02b2b64082f226fd1673f0ec31c22f9ff0cf7 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 07:03:34 -0400 Subject: [PATCH 12/64] Fix release date --- doc/changes/changes_0.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 14546ce..5f578a2 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2020-11-18 +# Virtual Schema for Snowflake 0.1.0, released 2024-??-?? Code name: First version From de099d4be20aa010dc6761f43b249ebee005f959 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 29 Aug 2024 07:12:40 -0400 Subject: [PATCH 13/64] fix dependency #s (why does PK not fix this automatically?) --- doc/changes/changes_0.1.0.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 5f578a2..cdf405d 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -42,16 +42,16 @@ This is the MVP release. * Added `com.exasol:project-keeper-maven-plugin:4.3.3` * Added `io.github.zlika:reproducible-build-maven-plugin:0.16` * Added `org.apache.maven.plugins:maven-assembly-plugin:3.7.1` -* Added `org.apache.maven.plugins:maven-clean-plugin:3.2.0` +* Added `org.apache.maven.plugins:maven-clean-plugin:2.5` * Added `org.apache.maven.plugins:maven-compiler-plugin:3.13.0` * Added `org.apache.maven.plugins:maven-dependency-plugin:3.6.1` -* Added `org.apache.maven.plugins:maven-deploy-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-deploy-plugin:2.7` * Added `org.apache.maven.plugins:maven-enforcer-plugin:3.5.0` * Added `org.apache.maven.plugins:maven-failsafe-plugin:3.2.5` -* Added `org.apache.maven.plugins:maven-install-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-install-plugin:2.4` * Added `org.apache.maven.plugins:maven-jar-plugin:3.4.1` -* Added `org.apache.maven.plugins:maven-resources-plugin:3.3.1` -* Added `org.apache.maven.plugins:maven-site-plugin:3.12.1` +* Added `org.apache.maven.plugins:maven-resources-plugin:2.6` +* Added `org.apache.maven.plugins:maven-site-plugin:3.3` * Added `org.apache.maven.plugins:maven-surefire-plugin:3.2.5` * Added `org.apache.maven.plugins:maven-toolchains-plugin:3.2.0` * Added `org.basepom.maven:duplicate-finder-maven-plugin:2.0.1` @@ -60,4 +60,4 @@ This is the MVP release. * Added `org.codehaus.mojo:versions-maven-plugin:2.16.2` * Added `org.jacoco:jacoco-maven-plugin:0.8.12` * Added `org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121` -* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` +* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` \ No newline at end of file From 2b350ac7e200ef09b783d1e4e859d1b34ea21fcf Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Wed, 4 Sep 2024 05:58:30 -0400 Subject: [PATCH 14/64] Added v1 of user guide --- doc/user_guide/snowflake_user_guide.md | 139 +++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/doc/user_guide/snowflake_user_guide.md b/doc/user_guide/snowflake_user_guide.md index e69de29..0400bff 100644 --- a/doc/user_guide/snowflake_user_guide.md +++ b/doc/user_guide/snowflake_user_guide.md @@ -0,0 +1,139 @@ +# Snowflake SQL Dialect User Guide + +[Snowflake](https://www.snowflake.com/) operates a platform that provides data storage via cloud computing and allows for data analysis. + +## Uploading the JDBC Driver to Exasol BucketFS + +1. Download the [SnowflakeJDBC driver](https://docs.snowflake.com/en/developer-guide/jdbc/jdbc-download). + +2. Upload the driver to BucketFS, see [BucketFS documentation](https://docs.exasol.com/db/latest/administration/on-premise/bucketfs/accessfiles.htm). + + Hint: Put the driver into folder `default/drivers/jdbc/` to register it for [ExaLoader](#registering-the-jdbc-driver-for-exaloader), too. + +## Registering the JDBC driver for ExaLoader + +In order to enable the ExaLoader to fetch data from the external database you must register the driver for ExaLoader as described in the [Installation procedure for JDBC drivers](https://github.com/exasol/docker-db/#installing-custom-jdbc-drivers). +1. ExaLoader expects the driver in BucketFS folder `default/drivers/jdbc`.
+ If you uploaded the driver for UDF to a different folder, then you need to [upload](#uploading-the-jdbc-driver-to-exasol-bucketfs) the driver again. +2. Additionally you need to create file `settings.cfg` and [upload](#uploading-the-jdbc-driver-to-exasol-bucketfs) it to the same folder in BucketFS: + +``` +DRIVERNAME=SNOWFLAKE_JDBC_DRIVER +JAR= +DRIVERMAIN=net.snowflake.client.jdbc.SnowflakeDriver +PREFIX=jdbc:snowflake: +FETCHSIZE=100000 +INSERTSIZE=-1 +``` + +| Variable | Description | +|----------|-----------------------------| +| `` | E.g. `snowflake-jdbc-3.16.1.jar` | + +## Installing the Adapter Script + +[Upload](https://docs.exasol.com/db/latest/administration/on-premise/bucketfs/accessfiles.htm) the latest available release of [Snowflake Virtual Schema JDBC Adapter](https://github.com/exasol/snowflake-virtual-schema/releases) to Bucket FS. + +Then create a schema to hold the adapter script. + +```sql +CREATE SCHEMA ADAPTER; +``` + +The SQL statement below creates the adapter script, defines the Java class that serves as entry point and tells the UDF framework where to find the libraries (JAR files) for Virtual Schema and database driver. + +```sql +--/ +CREATE OR REPLACE JAVA ADAPTER SCRIPT ADAPTER.JDBC_ADAPTER AS + %scriptclass com.exasol.adapter.RequestDispatcher; + %jar /buckets///virtual-schema-dist-12.0.0-snowflake-0.1.0.jar; +/ +``` + +## Defining a Named Connection + +Define the connection to the Snowflake database as shown below. We recommend using TLS to secure the connection. + +```sql +CREATE OR REPLACE CONNECTION SNOWFLAKE_CONNECTION +TO 'jdbc:snowflake://.snowflakecomputing.com' +USER '' +IDENTIFIED BY ''; +``` + +| Variable | Description | +|----------|-------------| + +| ` + USING ADAPTER.JDBC_ADAPTER + WITH + CATALOG_NAME = '' + SCHEMA_NAME = '' + CONNECTION_NAME = 'SNOWFLAKECONNECTION'; +``` + +| Variable | Description | +|----------|-----------------------------------------------------------------------------------------------------| +| `` | Name of the virtual schema you want to use. | +| `` | Name of the catalog, usally equivalent to the name of the Snowflake database. Please use UPPERCASE. | +| `` | Name of the database schema you want to use in the Snowflake database. Please use UPPERCASE. | + + +For additional parameters coming from the base library see also [Adapter Properties for JDBC-Based Virtual Schemas](https://github.com/exasol/virtual-schema-common-jdbc#adapter-properties-for-jdbc-based-virtual-schemas). + +## Data Types Conversion + +| Snowflake Data Type | Supported | Converted Exasol Data Type | Known limitations | +|--------------------------|--------------|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| +| BIGINT | ✓ | DECIMAL(19,0) | | +| BIGSERIAL | ✓ | DECIMAL(19,0) | | +| BIT | ✓ | BOOLEAN | | +| BIT VARYING | ✓ | VARCHAR(5) | | +| BOX | ✓ | VARCHAR(2000000) | | +| BYTEA | ✓ | VARCHAR(2000000) | | +| BOOLEAN | ✓ | BOOLEAN | | +| CHARACTER | ✓ | CHAR | | +| CHARACTER VARYING | ✓ | VARCHAR | | +| CIDR | ✓ | VARCHAR(2000000) | | +| CIRCLE | ✓ | VARCHAR(2000000) | | +| DATE | ✓ | DATE | | +| DOUBLE PRECISION | ✓ | DOUBLE | | +| INET | ✓ | VARCHAR(2000000) | | +| INTEGER | ✓ | DECIMAL(10,0) | | +| INTERVAL | ✓ | VARCHAR(2000000) | | +| JSON | ✓ | VARCHAR(2000000) | | +| JSONB | ✓ | VARCHAR(2000000) | | +| LINE | ✓ | VARCHAR(2000000) | | +| LSEG | ✓ | VARCHAR(2000000) | | +| MACADDR | ✓ | VARCHAR(2000000) | | +| MONEY | ✓ | DOUBLE | | +| NUMERIC | ✓ | VARCHAR(2000000) | Stored in Exasol as VARCHAR, because Snowflake NUMERIC values can exceed Exasol Decimal limit which makes it impossible to use Virtual Schemas. | +| PATH | ✓ | VARCHAR(2000000) | | +| POINT | ✓ | VARCHAR(2000000) | | +| POLYGON | ✓ | VARCHAR(2000000) | | +| REAL | ✓ | DOUBLE | | +| SMALLINT | ✓ | DECIMAL(5,0) | | +| SMALLSERIAL | ? (untested) | | | +| SERIAL | ? (untested) | | | +| TEXT | ✓ | VARCHAR(2000000) | | +| TIME | ✓ | VARCHAR(2000000) | | +| TIME WITH TIME ZONE | ✓ | VARCHAR(2000000) | | +| TIMESTAMP | ✓ | TIMESTAMP | | +| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP | | +| TSQUERY | ✓ | VARCHAR(2000000) | | +| TSVECTOR | ✓ | VARCHAR(2000000) | | +| UUID | ✓ | VARCHAR(2000000) | | +| XML | ✓ | VARCHAR(2000000) | | From 1ae1eaf6ebaaefc7f8b67659f8404fd041070943 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Wed, 4 Sep 2024 05:59:30 -0400 Subject: [PATCH 15/64] minor cleanup --- .../SnowflakeVirtualSchemaIntegrationTestSetup.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 707cffe..1762efe 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -198,10 +198,6 @@ private AdapterScript createAdapterScript(final ExasolSchema schema) { return schema.createAdapterScript(ADAPTER_SCRIPT_EXASOL, JAVA, content); } - // public SnowflakeObjectFactory getSnowflakeFactory() { - // return this.snowflakeFactory; - // } - public Statement getSnowflakeStatement() { return this.snowflakeStatement; } @@ -219,7 +215,6 @@ public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, // TODO add localstack support + cleanup final Map properties = new HashMap<>(Map.of("CATALOG_NAME", "TESTDB", // "SCHEMA_NAME", forSnowflakeSchema)); // - // "ACCOUNT_NAME", "bfcxnza-jg09523")); properties.putAll(additionalProperties); return this.exasolFactory .createVirtualSchemaBuilder("SNOWFLAKE_VIRTUAL_SCHEMA_" + (this.virtualSchemaCounter++)) From 347fe640bf774973da8551bcfb03b3fdb6ec8876 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 5 Sep 2024 04:53:35 -0400 Subject: [PATCH 16/64] fix link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ffe367..99866f9 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ If you want to set up a Virtual Schema for a different database system, please h ### Information for Users * [Virtual Schema User Guide](https://docs.exasol.com/database_concepts/virtual_schemas.htm) -* [Snowflake Dialect User Guide](doc/user_guide/Snowflake_user_guide.md) +* [Snowflake Dialect User Guide](doc/user_guide/snowflake_user_guide.md) * [List of supported capabilities](doc/generated/capabilities.md) * [Changelog](doc/changes/changelog.md) * [Dependencies](dependencies.md) From 9181585e13678f30cfa225b37b1bad9f2c52135e Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 13 Sep 2024 05:45:26 -0400 Subject: [PATCH 17/64] Adjustments to user guide --- doc/user_guide/snowflake_user_guide.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/doc/user_guide/snowflake_user_guide.md b/doc/user_guide/snowflake_user_guide.md index 0400bff..0c34aa3 100644 --- a/doc/user_guide/snowflake_user_guide.md +++ b/doc/user_guide/snowflake_user_guide.md @@ -24,7 +24,10 @@ DRIVERMAIN=net.snowflake.client.jdbc.SnowflakeDriver PREFIX=jdbc:snowflake: FETCHSIZE=100000 INSERTSIZE=-1 +NOSECURITY=YES + ``` +Make sure there's a newline at the end of the `settings.cfg` file, as shown above, or it will not be properly read out, the EXALoader will display an error message. | Variable | Description | |----------|-----------------------------| @@ -44,9 +47,10 @@ The SQL statement below creates the adapter script, defines the Java class that ```sql --/ -CREATE OR REPLACE JAVA ADAPTER SCRIPT ADAPTER.JDBC_ADAPTER AS +CREATE OR REPLACE JAVA ADAPTER SCRIPT ADAPTER.SNOWFLAKE_JDBC_ADAPTER AS %scriptclass com.exasol.adapter.RequestDispatcher; %jar /buckets///virtual-schema-dist-12.0.0-snowflake-0.1.0.jar; + %jar /buckets///drivers/jdbc/snowflake-jdbc-.jar; / ``` @@ -78,11 +82,11 @@ Use the following SQL command in Exasol database to create a Snowflake Virtual S ```sql CREATE VIRTUAL SCHEMA - USING ADAPTER.JDBC_ADAPTER + USING ADAPTER.SNOWFLAKE_JDBC_ADAPTER WITH CATALOG_NAME = '' SCHEMA_NAME = '' - CONNECTION_NAME = 'SNOWFLAKECONNECTION'; + CONNECTION_NAME = 'SNOWFLAKE_CONNECTION'; ``` | Variable | Description | From ee70cf220d435dcecd29d2a5be9bfdc1da3362d1 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 17 Sep 2024 06:21:21 -0400 Subject: [PATCH 18/64] Remove commented out code --- .../snowflake/SnowflakeColumnMetadataReader.java | 13 ------------- .../snowflake/SnowflakeSqlDialectTest.java | 9 --------- .../SnowflakeSqlGenerationVisitorTest.java | 12 ------------ .../SnowflakeTableMetadataReaderTest.java | 15 --------------- ...nowflakeVirtualSchemaIntegrationTestSetup.java | 5 ----- 5 files changed, 54 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java index ac24cb1..2dc8ecd 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java @@ -34,10 +34,6 @@ public SnowflakeColumnMetadataReader(final Connection connection, final AdapterP * * @return catalog name or null if metadata lookups are not limited by catalog */ -// @Override -// public String getCatalogNameFilter() { -// return this.properties.getDatabaseName(); -// } @Override public DataType mapJdbcType(final JDBCTypeDescription jdbcTypeDescription) { switch (jdbcTypeDescription.getJdbcType()) { @@ -70,20 +66,11 @@ protected boolean isVarBitColumn(final JDBCTypeDescription jdbcTypeDescription) @Override public String readColumnName(final ResultSet columns) throws SQLException { -// if (getIdentifierMapping().equals(CaseFolding.CONVERT_TO_UPPER)) { -// return super.readColumnName(columns).toUpperCase(); -// } else { return super.readColumnName(columns); -// } } @Override public String getSchemaNameFilter() { return this.properties.getSchemaName().toUpperCase(); - //return this.properties.getSchemaName().replace("_","\\_").toUpperCase(); } - -// CaseFolding getIdentifierMapping() { -// return SnowflakeIdentifierMapping.from(this.properties); -// } } \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java index eafa795..f268462 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java @@ -86,15 +86,6 @@ void testGetCapabilities() { VAR_POP, VAR_POP_DISTINCT, VAR_SAMP, VAR_SAMP_DISTINCT, GROUP_CONCAT)) // ); } -/* - @CsvSource({ "ABC, \"abc\"", // - "AbCde, \"abcde\"", // - "\"tableName, \"\"\"tablename\"" // - }) - @ParameterizedTest - void testApplyQuote(final String unquoted, final String quoted) { - assertThat(this.dialect.applyQuote(unquoted), equalTo(quoted)); - }*/ @ValueSource(strings = { "ab:E'ab'", "a'b:E'a''b'", "a''b:E'a''''b'", "'ab':E'''ab'''", "a\\\\b:E'a\\\\\\\\b'", "a\\'b:E'a\\\\''b'" }) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java index a843d5b..1f9a7e5 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java @@ -90,18 +90,6 @@ void testVisitSqlSelectListAnyValue() throws AdapterException { assertSqlNodeConvertedToOne(sqlSelectList, this.visitor); } -/* @Test - void testVisitSqlStatementSelect() throws AdapterException { - final SqlStatementSelect select = (SqlStatementSelect) DialectTestData.getTestSqlNode(); - assertThat(this.visitor.visit(select), // - equalTo("SELECT \"user_id\", " // - + "COUNT(\"url\") FROM \"test_schema\".\"clicks\" " // - + "WHERE 1 < \"user_id\" " // - + "GROUP BY \"user_id\" " // - + "HAVING 1 < COUNT(\"url\") " // - + "ORDER BY \"user_id\" LIMIT 10")); - }*/ - @Test void testVisitSqlFunctionAggregateGroupConcat() throws AdapterException { final SqlLiteralString argument = new SqlLiteralString("test"); diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java index 7934c65..32f3682 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReaderTest.java @@ -32,19 +32,4 @@ void beforeEach() { private void ignoreErrors(final String ignoreErrors) { this.rawProperties.put(IGNORE_ERRORS_PROPERTY, ignoreErrors); } - - - -/* @Test - void testIsUppercaseTableIncludedByMappingWithIgnoringUppercaseTables() { - ignoreErrors("SNOWFLAKE_UPPERCASE_TABLES"); - assertThat(this.reader.isTableIncludedByMapping("\"FooBar\""), equalTo(false)); - } - - @Test - void testIsUppercaseTableIncludedByMappingWithConvertToUpperNotIgnoringUppercaseTablesThrowsException() { - final RemoteMetadataReaderException exception = assertThrows(RemoteMetadataReaderException.class, - () -> this.reader.isTableIncludedByMapping("\"FooBar\"")); - assertThat(exception.getMessage(), containsString("E-VSSF-6")); - }*/ } \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 1762efe..cd2b30b 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -38,8 +38,6 @@ public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { private static final String PASSWORD_FILE = "password.txt"; private static final String ACCOUNTNAME_FILE = "accountname.txt"; private final Statement snowflakeStatement; - // private final LocalStackContainer snowflakeContainer = new - // LocalStackContainer(DockerImageName.parse("localstack/snowflake")); private final ExasolContainer> exasolContainer = new ExasolContainer<>( EXASOL_DOCKER_IMAGE_REFERENCE).withRequiredServices(ExasolService.BUCKETFS, ExasolService.UDF) .withReuse(true); @@ -104,9 +102,6 @@ private ConnectionDefinition getSnowflakeConnectionDefinition(final String conne // TODO add localstack support + cleanup private String getSnowflakeConnectionString(final String accountname) { - // final String connectionString = "jdbc:snowflake://" + this.exasolContainer.getHostIp() + ":" - // + this.snowflakeContainer.getMappedPort(SNOWFLAKE_PORT) + "/" - // + this.snowflakeContainer.getDatabaseName(); final String connectionString = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; return connectionString; } From 6dbf82da28e7b339b6869b024605694623229144 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 17 Sep 2024 06:21:37 -0400 Subject: [PATCH 19/64] Fix table formatting and small improvement. --- doc/user_guide/snowflake_user_guide.md | 94 +++++++++++++------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/doc/user_guide/snowflake_user_guide.md b/doc/user_guide/snowflake_user_guide.md index 0c34aa3..1ce757d 100644 --- a/doc/user_guide/snowflake_user_guide.md +++ b/doc/user_guide/snowflake_user_guide.md @@ -15,7 +15,7 @@ In order to enable the ExaLoader to fetch data from the external database you must register the driver for ExaLoader as described in the [Installation procedure for JDBC drivers](https://github.com/exasol/docker-db/#installing-custom-jdbc-drivers). 1. ExaLoader expects the driver in BucketFS folder `default/drivers/jdbc`.
If you uploaded the driver for UDF to a different folder, then you need to [upload](#uploading-the-jdbc-driver-to-exasol-bucketfs) the driver again. -2. Additionally you need to create file `settings.cfg` and [upload](#uploading-the-jdbc-driver-to-exasol-bucketfs) it to the same folder in BucketFS: +2. Additionally, you need to create file `settings.cfg` and [upload](#uploading-the-jdbc-driver-to-exasol-bucketfs) it to the same folder in BucketFS. Contents below: ``` DRIVERNAME=SNOWFLAKE_JDBC_DRIVER @@ -29,8 +29,8 @@ NOSECURITY=YES ``` Make sure there's a newline at the end of the `settings.cfg` file, as shown above, or it will not be properly read out, the EXALoader will display an error message. -| Variable | Description | -|----------|-----------------------------| +| Variable | Description | +|-----------------------------------------|----------------------------------| | `` | E.g. `snowflake-jdbc-3.16.1.jar` | ## Installing the Adapter Script @@ -89,11 +89,11 @@ CREATE VIRTUAL SCHEMA CONNECTION_NAME = 'SNOWFLAKE_CONNECTION'; ``` -| Variable | Description | -|----------|-----------------------------------------------------------------------------------------------------| +| Variable | Description | +|-------------------------|-----------------------------------------------------------------------------------------------------| | `` | Name of the virtual schema you want to use. | -| `` | Name of the catalog, usally equivalent to the name of the Snowflake database. Please use UPPERCASE. | -| `` | Name of the database schema you want to use in the Snowflake database. Please use UPPERCASE. | +| `` | Name of the catalog, usally equivalent to the name of the Snowflake database. Please use UPPERCASE. | +| `` | Name of the database schema you want to use in the Snowflake database. Please use UPPERCASE. | For additional parameters coming from the base library see also [Adapter Properties for JDBC-Based Virtual Schemas](https://github.com/exasol/virtual-schema-common-jdbc#adapter-properties-for-jdbc-based-virtual-schemas). @@ -101,43 +101,43 @@ For additional parameters coming from the base library see also [Adapter Propert ## Data Types Conversion | Snowflake Data Type | Supported | Converted Exasol Data Type | Known limitations | -|--------------------------|--------------|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| -| BIGINT | ✓ | DECIMAL(19,0) | | -| BIGSERIAL | ✓ | DECIMAL(19,0) | | -| BIT | ✓ | BOOLEAN | | -| BIT VARYING | ✓ | VARCHAR(5) | | -| BOX | ✓ | VARCHAR(2000000) | | -| BYTEA | ✓ | VARCHAR(2000000) | | -| BOOLEAN | ✓ | BOOLEAN | | -| CHARACTER | ✓ | CHAR | | -| CHARACTER VARYING | ✓ | VARCHAR | | -| CIDR | ✓ | VARCHAR(2000000) | | -| CIRCLE | ✓ | VARCHAR(2000000) | | -| DATE | ✓ | DATE | | -| DOUBLE PRECISION | ✓ | DOUBLE | | -| INET | ✓ | VARCHAR(2000000) | | -| INTEGER | ✓ | DECIMAL(10,0) | | -| INTERVAL | ✓ | VARCHAR(2000000) | | -| JSON | ✓ | VARCHAR(2000000) | | -| JSONB | ✓ | VARCHAR(2000000) | | -| LINE | ✓ | VARCHAR(2000000) | | -| LSEG | ✓ | VARCHAR(2000000) | | -| MACADDR | ✓ | VARCHAR(2000000) | | -| MONEY | ✓ | DOUBLE | | -| NUMERIC | ✓ | VARCHAR(2000000) | Stored in Exasol as VARCHAR, because Snowflake NUMERIC values can exceed Exasol Decimal limit which makes it impossible to use Virtual Schemas. | -| PATH | ✓ | VARCHAR(2000000) | | -| POINT | ✓ | VARCHAR(2000000) | | -| POLYGON | ✓ | VARCHAR(2000000) | | -| REAL | ✓ | DOUBLE | | -| SMALLINT | ✓ | DECIMAL(5,0) | | -| SMALLSERIAL | ? (untested) | | | -| SERIAL | ? (untested) | | | -| TEXT | ✓ | VARCHAR(2000000) | | -| TIME | ✓ | VARCHAR(2000000) | | -| TIME WITH TIME ZONE | ✓ | VARCHAR(2000000) | | -| TIMESTAMP | ✓ | TIMESTAMP | | -| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP | | -| TSQUERY | ✓ | VARCHAR(2000000) | | -| TSVECTOR | ✓ | VARCHAR(2000000) | | -| UUID | ✓ | VARCHAR(2000000) | | -| XML | ✓ | VARCHAR(2000000) | | +|--------------------------|--------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| +| BIGINT | ✓ | DECIMAL(19,0) | | +| BIGSERIAL | ✓ | DECIMAL(19,0) | | +| BIT | ✓ | BOOLEAN | | +| BIT VARYING | ✓ | VARCHAR(5) | | +| BOX | ✓ | VARCHAR(2000000) | | +| BYTEA | ✓ | VARCHAR(2000000) | | +| BOOLEAN | ✓ | BOOLEAN | | +| CHARACTER | ✓ | CHAR | | +| CHARACTER VARYING | ✓ | VARCHAR | | +| CIDR | ✓ | VARCHAR(2000000) | | +| CIRCLE | ✓ | VARCHAR(2000000) | | +| DATE | ✓ | DATE | | +| DOUBLE PRECISION | ✓ | DOUBLE | | +| INET | ✓ | VARCHAR(2000000) | | +| INTEGER | ✓ | DECIMAL(10,0) | | +| INTERVAL | ✓ | VARCHAR(2000000) | | +| JSON | ✓ | VARCHAR(2000000) | | +| JSONB | ✓ | VARCHAR(2000000) | | +| LINE | ✓ | VARCHAR(2000000) | | +| LSEG | ✓ | VARCHAR(2000000) | | +| MACADDR | ✓ | VARCHAR(2000000) | | +| MONEY | ✓ | DOUBLE | | +| NUMERIC | ✓ | VARCHAR(2000000) | Stored in Exasol as VARCHAR, because Snowflake NUMERIC values can exceed Exasol Decimal limit which makes it impossible to use Virtual Schemas. | +| PATH | ✓ | VARCHAR(2000000) | | +| POINT | ✓ | VARCHAR(2000000) | | +| POLYGON | ✓ | VARCHAR(2000000) | | +| REAL | ✓ | DOUBLE | | +| SMALLINT | ✓ | DECIMAL(5,0) | | +| SMALLSERIAL | ? (untested) | | | +| SERIAL | ? (untested) | | | +| TEXT | ✓ | VARCHAR(2000000) | | +| TIME | ✓ | VARCHAR(2000000) | | +| TIME WITH TIME ZONE | ✓ | VARCHAR(2000000) | | +| TIMESTAMP | ✓ | TIMESTAMP | | +| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP | | +| TSQUERY | ✓ | VARCHAR(2000000) | | +| TSVECTOR | ✓ | VARCHAR(2000000) | | +| UUID | ✓ | VARCHAR(2000000) | | +| XML | ✓ | VARCHAR(2000000) | | From 52d8787180d882c3b2207e8e60a68b47063e8223 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 20 Sep 2024 06:45:09 -0400 Subject: [PATCH 20/64] Added different mapping and conversions for: - timestamp with timezone -> timezone - warning for NUMBER with precision > 36 - 'character' is an alias for varchar in snowflake so it gets converted to varchar and there's no padding --- .../SnowflakeColumnMetadataReader.java | 4 +++ .../SnowflakeSqlGenerationVisitor.java | 29 +++++++++++++++---- .../snowflake/SnowflakeSqlDialectIT.java | 14 ++++----- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java index 2dc8ecd..da88670 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java @@ -10,6 +10,8 @@ import com.exasol.adapter.jdbc.JDBCTypeDescription; import com.exasol.adapter.metadata.DataType; +import static com.exasol.adapter.metadata.DataType.ExaCharset.UTF8; + /** * This class implements Snowflake-specific reading of column metadata. */ @@ -43,6 +45,8 @@ public DataType mapJdbcType(final JDBCTypeDescription jdbcTypeDescription) { case Types.DISTINCT: case Types.BINARY: return DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8); + case Types.TIMESTAMP_WITH_TIMEZONE: + return DataType.createTimestamp(false); default: return super.mapJdbcType(jdbcTypeDescription); } diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java index 7d48a29..9f45ccd 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java @@ -3,9 +3,13 @@ import java.util.*; import com.exasol.adapter.AdapterException; +import com.exasol.adapter.adapternotes.ColumnAdapterNotes; +import com.exasol.adapter.adapternotes.ColumnAdapterNotesJsonConverter; import com.exasol.adapter.dialects.SqlDialect; import com.exasol.adapter.dialects.rewriting.SqlGenerationContext; import com.exasol.adapter.dialects.rewriting.SqlGenerationVisitor; +import com.exasol.adapter.metadata.ColumnMetadata; +import com.exasol.adapter.metadata.DataType; import com.exasol.adapter.sql.*; /** @@ -48,9 +52,18 @@ public String visit(final SqlColumn column) throws AdapterException { private String getColumnProjectionString(final SqlColumn column, final String projectionString) throws AdapterException { - return super.isDirectlyInSelectList(column) // - ? buildColumnProjectionString(getTypeNameFromColumn(column), projectionString) // - : projectionString; + + if (super.isDirectlyInSelectList(column)) { // + final ColumnAdapterNotesJsonConverter converter = ColumnAdapterNotesJsonConverter.getInstance(); + ColumnMetadata metaData = column.getMetadata(); + DataType mappedType = metaData.getType(); + ColumnAdapterNotes columnAdapterNotes= converter.convertFromJsonToColumnAdapterNotes(metaData.getAdapterNotes(), column.getName()); + String sourceTypeName = columnAdapterNotes.getTypeName(); + + return buildColumnProjectionString(sourceTypeName,mappedType, projectionString); // + } else { + return projectionString; + } } @Override @@ -167,8 +180,14 @@ private String getPosixTime(final List argumentsSql) { return "EXTRACT(EPOCH FROM " + argumentsSql.get(0) + ")"; } - private String buildColumnProjectionString(final String typeName, final String projectionString) { - if (checkIfNeedToCastToVarchar(typeName)) { + private String buildColumnProjectionString(final String typeName,DataType mappedType, final String projectionString) { + if (typeName.startsWith("NUMBER") && mappedType.getExaDataType() == DataType.ExaDataType.VARCHAR ){ + return "'Number precision not supported'"; + } + else if (typeName.startsWith("TIMESTAMPTZ")) { + return "TO_TIMESTAMP_NTZ(" + projectionString +")"; + } + else if (checkIfNeedToCastToVarchar(typeName)) { return "CAST(" + projectionString + " as VARCHAR )"; } else if (typeName.startsWith("smallserial")) { return "CAST(" + projectionString + " as SMALLINT )"; diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index 9dcf1c0..1b76fe2 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -7,8 +7,9 @@ import java.sql.*; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.*; import java.util.Date; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import org.hamcrest.MatcherAssert; @@ -85,7 +86,7 @@ private static void createSnowflakeTestTableAllDataTypes(final Statement stateme + "myBoolean BOOLEAN, " // // + "myBox BOX, " // // + "myBytea BYTEA, " // - + "myCharacter CHARACTER(1000), " // + + "myCharacter CHARACTER(1000), " // ALIAS FOR NVARCHAR IN SNOWFLAKE, SAME THING, NO PADDING + "myCharacterVar CHARACTER, " // // + "myCidr CIDR, " // // + "myCircle CIRCLE, " // @@ -306,7 +307,7 @@ void testCountAll() throws SQLException { @Test void testDatatypeBigint() throws SQLException { - assertSingleValue("myBigint", "DECIMAL(19,0)", "10000000000"); + assertSingleValue("myBigint", "VARCHAR(2000000) UTF8", "Number precision not supported"); } @Test @@ -316,9 +317,8 @@ void testDatatypeBoolean() throws SQLException { @Test void testDatatypeCharacter() throws SQLException { - final String empty = " "; - final String expected = "hajksdf" + String.join("", Collections.nCopies(993, empty)); - assertSingleValue("myCharacter", "CHAR(1000) UTF8", expected); + final String expected = "hajksdf"; + assertSingleValue("myCharacter", "VARCHAR(1000) UTF8", expected); } @Test @@ -354,7 +354,7 @@ void testDatatypeReal() throws SQLException { @Test void testDatatypeSmallInt() throws SQLException { - assertSingleValue("mySmallint", "DECIMAL(5,0)", 100); + assertSingleValue("mySmallint", "VARCHAR(2000000) UTF8", "Number precision not supported"); } @Test From cd391867ffd65a2fd6bcc7246b036a50086111bc Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 20 Sep 2024 08:12:24 -0400 Subject: [PATCH 21/64] fix error code config, add snowflake package --- error_code_config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/error_code_config.yml b/error_code_config.yml index 08ef8cc..71b9803 100644 --- a/error_code_config.yml +++ b/error_code_config.yml @@ -1,5 +1,6 @@ error-tags: VSSF: packages: + - com.exasol.adapter.dialects.snowflake - com.exasol.closeafterall highest-index: 9 From 3f6dfa0af081bc20a9eba282fa2e8b8f54ecc5e2 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 20 Sep 2024 08:43:26 -0400 Subject: [PATCH 22/64] add randomised db name addendum to allow for simultaneous integration test runs. --- .../snowflake/SnowflakeSqlDialectIT.java | 12 ++++++++- ...lakeVirtualSchemaIntegrationTestSetup.java | 26 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index 1b76fe2..c98ee16 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -45,7 +45,7 @@ class SnowflakeSqlDialectIT { static void beforeAll() throws SQLException { final Statement statementSnowflake = SETUP.getSnowflakeStatement(); try { - statementSnowflake.execute("CREATE DATABASE " + "TESTDB"); + statementSnowflake.execute("CREATE DATABASE " + SETUP.getDatabaseName()); } catch (final Exception e) { } @@ -68,6 +68,16 @@ static void beforeAll() throws SQLException { exasolSchema = SETUP.getExasolFactory().createSchema("EXASOL_TEST_SCHEMA"); } + @AfterAll + static void afterAll() throws SQLException { + final Statement statementSnowflake = SETUP.getSnowflakeStatement(); + try { + statementSnowflake.execute("DROP DATABASE " + SETUP.getDatabaseName() + " CASCADE;"); + } catch (final Exception e) { + + } + } + private static void createSnowflakeTestTableSimple(final Statement statementSnowflake) throws SQLException { final String qualifiedTableName = SCHEMA_SNOWFLAKE + "." + TABLE_SNOWFLAKE_SIMPLE; statementSnowflake.execute("CREATE TABLE " + qualifiedTableName + " (x NUMBER(36,0))"); diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index cd2b30b..d67f0ba 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -52,9 +52,27 @@ public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { private String userName; private String password; private String accountName; + private String databaseName; + + public String randomDbAddendum() { + final int leftLimit = 97; // letter 'a' + final int rightLimit = 122; // letter 'z' + final int targetStringLength = 4; + final Random random = new Random(); + + final String generatedString = random.ints(leftLimit, rightLimit + 1).limit(targetStringLength) + .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString(); + + return generatedString; + } + + public String getDatabaseName() { + return databaseName; + } SnowflakeVirtualSchemaIntegrationTestSetup() { try { + this.databaseName = "TESTDB" + randomDbAddendum().toUpperCase(); this.exasolContainer.start(); // TODO add localstack support // this.snowflakeContainer.start(); @@ -107,8 +125,8 @@ private String getSnowflakeConnectionString(final String accountname) { } // TODO add localstack support + cleanup - private static Connection getSnowflakeConnection(final String username, final String password, - final String accountname) throws SQLException { + private Connection getSnowflakeConnection(final String username, final String password, final String accountname) + throws SQLException { // TODO refactor this whole thing and remove secrets + add localstack support try { Class.forName("net.snowflake.client.jdbc.SnowflakeDriver"); @@ -121,7 +139,7 @@ private static Connection getSnowflakeConnection(final String username, final St properties.put("user", username); // replace "" with your username properties.put("password", password); // replace "" with your password properties.put("account", accountname); // replace "" with your account name - properties.put("db", "TESTDB"); // replace "" with target database name + properties.put("db", this.databaseName); // replace "" with target database name properties.put("schema", "TESTSCHEMA"); // replace "" with target schema name // properties.put("tracing", "on"); @@ -208,7 +226,7 @@ public ExasolContainer> getExasolContainer() { public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, final Map additionalProperties) { // TODO add localstack support + cleanup - final Map properties = new HashMap<>(Map.of("CATALOG_NAME", "TESTDB", // + final Map properties = new HashMap<>(Map.of("CATALOG_NAME", databaseName, // "SCHEMA_NAME", forSnowflakeSchema)); // properties.putAll(additionalProperties); return this.exasolFactory From c22ae4bde43a06cf4a4920d492c5db41d97ae396 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 23 Sep 2024 04:57:10 -0400 Subject: [PATCH 23/64] Remove link to capabilities for now as SIT not added to project yet. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 99866f9..0d79772 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,6 @@ If you want to set up a Virtual Schema for a different database system, please h * [Virtual Schema User Guide](https://docs.exasol.com/database_concepts/virtual_schemas.htm) * [Snowflake Dialect User Guide](doc/user_guide/snowflake_user_guide.md) -* [List of supported capabilities](doc/generated/capabilities.md) * [Changelog](doc/changes/changelog.md) * [Dependencies](dependencies.md) From ed7d94be52df51537dcab9b90801c97d87c122ce Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 23 Sep 2024 04:57:38 -0400 Subject: [PATCH 24/64] Add credentials step to release workflow --- .github/workflows/release.yml | 11 +++++++++++ .project-keeper.yml | 17 +++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2a8bbf7..b7a2687 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -104,6 +104,17 @@ jobs: env: { GITHUB_TOKEN: '${{ github.token }}' } + - name: Configure Snowflake credentials + id: configure-snowflake-credentials + run: | + echo "$USERNAME" > username.txt + echo "$ACCOUNTNAME" > accountname.txt + echo "$PASSWORD" > password.txt + env: { + USERNAME: '${{ secrets.USERNAME }}', + ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', + PASSWORD: '${{ secrets.PASSWORD }}' + } - { name: Build project, id: build, diff --git a/.project-keeper.yml b/.project-keeper.yml index 06d9890..c2672a3 100644 --- a/.project-keeper.yml +++ b/.project-keeper.yml @@ -19,6 +19,23 @@ build: # Configure Snowflake credentials - action: INSERT_AFTER stepId: enable-testcontainer-reuse + content: + name: Configure Snowflake credentials + id: configure-snowflake-credentials + run: | + echo "$USERNAME" > username.txt + echo "$ACCOUNTNAME" > accountname.txt + echo "$PASSWORD" > password.txt + env: { + USERNAME: '${{ secrets.USERNAME }}', + ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', + PASSWORD: '${{ secrets.PASSWORD }}' + } + - name: release.yml + stepCustomizations: + # Configure Snowflake credentials + - action: INSERT_AFTER + stepId: verify-release content: name: Configure Snowflake credentials id: configure-snowflake-credentials From 7f6ee5a01dafb1847cefe442c53832296acc091d Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 23 Sep 2024 04:57:54 -0400 Subject: [PATCH 25/64] Add release date --- doc/changes/changes_0.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index cdf405d..273152d 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2024-??-?? +# Virtual Schema for Snowflake 0.1.0, released 2024-09-23 Code name: First version From 10c2417b40b6bfbd818da3e7a60b14e2a0be8871 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 24 Sep 2024 09:12:08 -0400 Subject: [PATCH 26/64] cleanup todos + code in comments + formatting --- .../SnowflakeColumnMetadataReader.java | 3 - .../snowflake/SnowflakeSqlDialect.java | 1 - .../snowflake/SnowflakeSqlDialectIT.java | 57 ++----------------- ...lakeVirtualSchemaIntegrationTestSetup.java | 23 ++------ 4 files changed, 9 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java index da88670..f2f9ae2 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java @@ -5,13 +5,10 @@ import com.exasol.adapter.AdapterProperties; import com.exasol.adapter.dialects.IdentifierConverter; -//import com.exasol.adapter.dialects.snowflake.SnowflakeIdentifierMapping.CaseFolding; import com.exasol.adapter.jdbc.BaseColumnMetadataReader; import com.exasol.adapter.jdbc.JDBCTypeDescription; import com.exasol.adapter.metadata.DataType; -import static com.exasol.adapter.metadata.DataType.ExaCharset.UTF8; - /** * This class implements Snowflake-specific reading of column metadata. */ diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java index 7c2574c..312b63c 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java @@ -100,7 +100,6 @@ private static ScalarFunctionCapability[] getEnabledScalarFunctionCapabilities() */ public SnowflakeSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) { super(connectionFactory, properties, // - //Set.of(SCHEMA_NAME_PROPERTY, DATABASE_NAME_PROPERTY, ACCOUNT_NAME_PROPERTY), // Set.of(SCHEMA_NAME_PROPERTY, CATALOG_NAME_PROPERTY, ACCOUNT_NAME_PROPERTY), // List.of()); } diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index c98ee16..9507be4 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -23,7 +23,7 @@ import com.exasol.matcher.TypeMatchMode; @Tag("integration") -@ExtendWith({ CloseAfterAllExtension.class }) +@ExtendWith({CloseAfterAllExtension.class}) class SnowflakeSqlDialectIT { @CloseAfterAll private static final SnowflakeVirtualSchemaIntegrationTestSetup SETUP = new SnowflakeVirtualSchemaIntegrationTestSetup(); @@ -90,86 +90,37 @@ private static void createSnowflakeTestTableAllDataTypes(final Statement stateme final String createAllDatatypesTableStatement = "CREATE TABLE " + qualifiedTableName // + " (" // + "myBigint BIGINT, " // - // + "myBigserial BIGSERIAL, " //does not exist in SNOWFLAKE - // + "myBit BIT, " //BIT does not exist in SNOWFLAKE, use INT instead - // + "myBitVar BIT, " //BIT does not exist in SNOWFLAKE, use INT instead + "myBoolean BOOLEAN, " // - // + "myBox BOX, " // - // + "myBytea BYTEA, " // + "myCharacter CHARACTER(1000), " // ALIAS FOR NVARCHAR IN SNOWFLAKE, SAME THING, NO PADDING + "myCharacterVar CHARACTER, " // - // + "myCidr CIDR, " // - // + "myCircle CIRCLE, " // + "myDate DATE, " // + "myDouble DOUBLE PRECISION, " // - // + "myInet INET, " // - + "myInteger NUMBER(36,0), " // INT (EGER) has (38,0) precision and scale in snowflake, Exasol has - // (36,0) - // as a max. The integer datatype causes problems with the EXALOADER. - // TODO: demonstrate this to TB - // + "myInterval INTERVAL, " // - // + "myJson JSON, " // - // + "myJsonB JSONB, " // - // + "myLine LINE, " // - // + "myLseg LSEG, " // - // + "myMacAddr MACADDR, " // - // + "myMoney MONEY, " // + + "myInteger NUMBER(36,0), " // INT(EGER) has (38,0) precision and scale in snowflake, Exasol has (36,0) as a max. The integer datatype causes problems with the EXALOADER. + "myNumeric NUMERIC(36, 10), " // same as NUMBER IN snowflake - // + "myPath PATH, " // - // + "myPoint POINT, " // - // + "myPolygon POLYGON, " // + "myReal REAL, " // + "mySmallint SMALLINT, " // + "myText TEXT, " // + "myTime TIME, " // - // + "myTimeWithTimeZone TIME WITH TIME ZONE, " //DOES NOT EXIST IN SNOWFLAKE + // TIME WITH TIME ZONE DOES NOT EXIST IN SNOWFLAKE + "myTimestamp TIMESTAMP, " // + "myTimestampWithTimeZone TIMESTAMP_TZ " // TIMESTAMP WITH TIME ZONE - // + "myTsquery TSQUERY, " // - // + "myTsvector VECTOR, " // - // + "myUuid UUID, " //SUBTYPE OF STRING IN SNOWFLAKE - // + "myXml XML " //DOES NOT EXIST IN SNOWFLAKE + ")"; statementSnowflake.execute(createAllDatatypesTableStatement); final String fillAllDatabaseTypesStatement = ("INSERT INTO " + qualifiedTableName + " VALUES (" // + "10000000000, " // myBigint - // + "nextval('" + qualifiedTableName + "_myBigserial_seq'::regclass), " // myBigserial - // + "B'1', " // myBit - // + "B'0', " // myBitVar + "false, " // myBoolean - // + "'( ( 1 , 8 ) , ( 4 , 16 ) )', " // myBox - // + "E'\\\\000'::bytea, " // myBytea + "'hajksdf', " // myCharacter - + "'h', " // myCharacterVar - // + "'192.168.100.128/25'::cidr, " // myCidr - // + "'( ( 1 , 5 ) , 3 )'::circle, " // myCircle + + "'h', " // myCharacterVar // + "'192.168.100.128/25'::cidr, " // myCidr + "'2010-01-01', " // myDate + "192189234.1723854, " // myDouble - // + "'192.168.100.128'::inet, " // myInet + "7189234, " // myInteger - // + "INTERVAL '1' YEAR, " // myInterval - // + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::json, " // myJson - // + "'{\"bar\": \"baz\", \"balance\": 7.77, \"active\": false}'::jsonb, " // myJsonB - // + "'{ 1, 2, 3 }'::line, " // myLine - // + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::lseg, " // myLseg - // + "'08:00:2b:01:02:03'::macaddr, " // myMacAddr - // + "100.01, " // myMoney + "24.23, " // myNumeric - // + "'[ ( 1 , 2 ) , ( 3 , 4 ) ]'::path, " // myPath - // + "'( 1 , 3 )'::point, " // myPoint - // + "'( ( 1 , 2 ) , (2,4),(3,7) )'::polygon, " // myPolygon + "10.12, " // myReal + "100, " // mySmallint + "'This cat is super cute', " // myText + "'11:11:11', " // myTime - // + "'11:11:11 +01:00', " // myTimeWithTimeZone + "'2010-01-01 11:11:11', " // myTimestamp + "'2010-01-01 11:11:11 +01:00' " // myTimestampwithtimezone - // + "'fat & rat'::tsquery, " // myTsquery - // + "VECTOR('english', 'The Fat Rats'), " // myTsvector - // + "'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid, " // myUuid - // + "XMLPARSE (DOCUMENT 'Manual...') " // myXml + ")"); statementSnowflake.execute(fillAllDatabaseTypesStatement); } diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index d67f0ba..fb52f02 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -46,7 +46,6 @@ public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { private final AdapterScript adapterScript; private final ConnectionDefinition connectionDefinition; private final ExasolObjectFactory exasolFactory; - // private final SnowflakeObjectFactory snowflakeFactory; private final Connection snowflakeConnection; private int virtualSchemaCounter = 0; private String userName; @@ -74,18 +73,14 @@ public String getDatabaseName() { try { this.databaseName = "TESTDB" + randomDbAddendum().toUpperCase(); this.exasolContainer.start(); - // TODO add localstack support - // this.snowflakeContainer.start(); final Bucket bucket = this.exasolContainer.getDefaultBucket(); uploadDriverToBucket(this.exasolContainer); uploadVsJarToBucket(bucket); this.exasolConnection = this.exasolContainer.createConnection(""); this.exasolStatement = this.exasolConnection.createStatement(); getTestCredentials(); - // TODO add localstack support + cleanup - this.snowflakeConnection = getSnowflakeConnection(userName, password, accountName);// this.snowflakeContainer.createConnection(""); - this.snowflakeStatement = snowflakeConnection.createStatement();// this.snowflakeConnection.createStatement(); - + this.snowflakeConnection = getSnowflakeConnection(userName, password, accountName); + this.snowflakeStatement = snowflakeConnection.createStatement(); final String hostIpAddress = getTestHostIpFromInsideExasol(); assert (hostIpAddress != null); final UdfTestSetup udfTestSetup = new UdfTestSetup(hostIpAddress, this.exasolContainer.getDefaultBucket(), @@ -93,11 +88,8 @@ public String getDatabaseName() { this.exasolFactory = new ExasolObjectFactory(this.exasolContainer.createConnection(""), ExasolObjectConfiguration.builder().withJvmOptions(udfTestSetup.getJvmOptions()).build()); final ExasolSchema exasolSchema = this.exasolFactory.createSchema(SCHEMA_EXASOL); - // this.snowflakeFactory = new SnowflakeObjectFactory(this.snowflakeConnection); this.adapterScript = createAdapterScript(exasolSchema); - // TODO add localstack support + cleanup final String connectionString = getSnowflakeConnectionString(accountName); - // TODO add localstack support + cleanup connectionDefinition = getSnowflakeConnectionDefinition(connectionString, userName, password); } catch (final SQLException | BucketAccessException | TimeoutException exception) { throw new IllegalStateException("Failed to created snowflake test setup.", exception); @@ -109,25 +101,21 @@ public String getDatabaseName() { } } - // TODO add localstack support + cleanup private ConnectionDefinition getSnowflakeConnectionDefinition(final String connectionString, final String username, - final String password) { + final String password) { final ConnectionDefinition connectionDefinition; connectionDefinition = this.exasolFactory.createConnectionDefinition("SNOWFLAKE_CONNECTION", connectionString, username, password); return connectionDefinition; } - // TODO add localstack support + cleanup private String getSnowflakeConnectionString(final String accountname) { final String connectionString = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; return connectionString; } - // TODO add localstack support + cleanup private Connection getSnowflakeConnection(final String username, final String password, final String accountname) throws SQLException { - // TODO refactor this whole thing and remove secrets + add localstack support try { Class.forName("net.snowflake.client.jdbc.SnowflakeDriver"); } catch (final ClassNotFoundException ex) { @@ -147,8 +135,7 @@ private Connection getSnowflakeConnection(final String username, final String pa String connectStr = System.getenv("SF_JDBC_CONNECT_STRING"); // use the default connection string if it is not set in environment if (connectStr == null) { - connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your - // account name + connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your account name } return DriverManager.getConnection(connectStr, properties); } @@ -224,7 +211,7 @@ public ExasolContainer> getExasolContainer() { } public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, - final Map additionalProperties) { + final Map additionalProperties) { // TODO add localstack support + cleanup final Map properties = new HashMap<>(Map.of("CATALOG_NAME", databaseName, // "SCHEMA_NAME", forSnowflakeSchema)); // From 935cbd1c20f5f7c3bd6bf3f2501f9a6fe4c896bf Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 24 Sep 2024 09:12:39 -0400 Subject: [PATCH 27/64] Changed release date --- doc/changes/changes_0.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 273152d..46e5352 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2024-09-23 +# Virtual Schema for Snowflake 0.1.0, released 2024-09-24 Code name: First version From 8c79371b1d2fbc6295c4c334b5d62937ed83ddcf Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Wed, 25 Sep 2024 03:55:04 -0400 Subject: [PATCH 28/64] set release date --- doc/changes/changes_0.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 46e5352..d015703 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2024-09-24 +# Virtual Schema for Snowflake 0.1.0, released 2024-09-25 Code name: First version From 6e8561d21e00fd1fe9dfa85ff741fc7a057933ce Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Wed, 25 Sep 2024 03:57:20 -0400 Subject: [PATCH 29/64] Update changes doc to make it a little less cryptic. --- doc/changes/changes_0.1.0.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index d015703..9bd4687 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,14 +1,16 @@ # Virtual Schema for Snowflake 0.1.0, released 2024-09-25 -Code name: First version +Code name: First version of the Snowflake virtual schema ## Summary -This is the MVP release. +This is the first version of the virtual schema for Snowflake. +There might still be issues and the project is subject to further testing. +Consider this a first and early-access release. ## Features -* #1: Releasing the MVP +* #1: Releasing the MVP (minimum viable product) ## Dependency Updates From b61350793053285e234b41b5d8cab22aa3130d95 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 26 Sep 2024 06:59:14 -0400 Subject: [PATCH 30/64] PR review feedback (1) - update .gitattributes - remove stale todo comments - update exasolDbversions in project-keeper.yml --- .gitattributes | 4 +--- .github/workflows/ci-build.yml | 6 +++--- .project-keeper.yml | 4 ++-- .../SnowflakeVirtualSchemaIntegrationTestSetup.java | 3 --- .../com/exasol/adapter/dialects/snowflake/TestConfig.java | 4 ++++ 5 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java diff --git a/.gitattributes b/.gitattributes index 94e0086..99f7c54 100644 --- a/.gitattributes +++ b/.gitattributes @@ -6,8 +6,6 @@ doc/changes/changelog.md linguist-genera .github/workflows/ci-build-next-java.yml linguist-generated=true .github/workflows/dependencies_check.yml linguist-generated=true .github/workflows/dependencies_update.yml linguist-generated=true -.github/workflows/release_droid_print_quick_checksum.yml linguist-generated=true -.github/workflows/release_droid_upload_github_release_assets.yml linguist-generated=true -.github/workflows/release_droid_prepare_original_checksum.yml linguist-generated=true +.github/workflows/release.yml linguist-generated=true .settings/org.eclipse.jdt.core.prefs linguist-generated=true .settings/org.eclipse.jdt.ui.prefs linguist-generated=true diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 268fa2b..67fcb95 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -25,12 +25,12 @@ jobs: fail-fast: false matrix: exasol_db_version: [ - 7.1.25, - 8.24.0 + 8.31.0, + 7.1.29 ] env: { - DEFAULT_EXASOL_DB_VERSION: 7.1.25 + DEFAULT_EXASOL_DB_VERSION: 8.31.0 } steps: - name: Free Disk Space diff --git a/.project-keeper.yml b/.project-keeper.yml index c2672a3..6a683c0 100644 --- a/.project-keeper.yml +++ b/.project-keeper.yml @@ -11,8 +11,8 @@ build: runnerOs: ubuntu-20.04 freeDiskSpace: false exasolDbVersions: - - "7.1.25" - - "8.24.0" + - "8.31.0" + - "7.1.29" workflows: - name: ci-build.yml stepCustomizations: diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index fb52f02..617516e 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -212,7 +212,6 @@ public ExasolContainer> getExasolContainer() { public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, final Map additionalProperties) { - // TODO add localstack support + cleanup final Map properties = new HashMap<>(Map.of("CATALOG_NAME", databaseName, // "SCHEMA_NAME", forSnowflakeSchema)); // properties.putAll(additionalProperties); @@ -234,8 +233,6 @@ public void close() { this.snowflakeStatement.close(); this.snowflakeConnection.close(); this.exasolContainer.stop(); - // TODO add localstack support + cleanup - // this.snowflakeContainer.stop(); } catch (final SQLException exception) { throw new IllegalStateException("Failed to stop test setup.", exception); } diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java b/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java new file mode 100644 index 0000000..9b116e0 --- /dev/null +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java @@ -0,0 +1,4 @@ +package com.exasol.adapter.dialects.snowflake; + +public class TestConfig { +} From 65a8aa1edf7a0ed310d21f3fd77f3f8f381c28b2 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 26 Sep 2024 07:00:25 -0400 Subject: [PATCH 31/64] PR review feedback (2) - Use TestConfig + test.properties file instead of 3 different files for accountname, username & password --- .github/workflows/ci-build.yml | 13 ++--- .github/workflows/release.yml | 15 ++--- .gitignore | 4 +- .project-keeper.yml | 27 ++++----- ...lakeVirtualSchemaIntegrationTestSetup.java | 27 ++------- .../dialects/snowflake/TestConfig.java | 55 ++++++++++++++++++- 6 files changed, 82 insertions(+), 59 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 67fcb95..f29eed1 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -70,14 +70,11 @@ jobs: - name: Configure Snowflake credentials id: configure-snowflake-credentials run: | - echo "$USERNAME" > username.txt - echo "$ACCOUNTNAME" > accountname.txt - echo "$PASSWORD" > password.txt - env: { - USERNAME: '${{ secrets.USERNAME }}', - ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', - PASSWORD: '${{ secrets.PASSWORD }}' - } + cat > test.properties < username.txt - echo "$ACCOUNTNAME" > accountname.txt - echo "$PASSWORD" > password.txt - env: { - USERNAME: '${{ secrets.USERNAME }}', - ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', - PASSWORD: '${{ secrets.PASSWORD }}' - } + run: |- + cat > test.properties < username.txt - echo "$ACCOUNTNAME" > accountname.txt - echo "$PASSWORD" > password.txt - env: { - USERNAME: '${{ secrets.USERNAME }}', - ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', - PASSWORD: '${{ secrets.PASSWORD }}' - } + cat > test.properties < username.txt - echo "$ACCOUNTNAME" > accountname.txt - echo "$PASSWORD" > password.txt - env: { - USERNAME: '${{ secrets.USERNAME }}', - ACCOUNTNAME: '${{ secrets.ACCOUNTNAME }}', - PASSWORD: '${{ secrets.PASSWORD }}' - } \ No newline at end of file + cat > test.properties <> exasolContainer = new ExasolContainer<>( EXASOL_DOCKER_IMAGE_REFERENCE).withRequiredServices(ExasolService.BUCKETFS, ExasolService.UDF) @@ -141,25 +139,10 @@ private Connection getSnowflakeConnection(final String username, final String pa } private void getTestCredentials() throws IOException { - if (!Files.exists(Path.of(USERNAME_FILE))) { - throw new IllegalStateException("Could not find " + USERNAME_FILE - + ". Please create a Snowflake account, get the username and store it in this project in " - + USERNAME_FILE + "."); - } - if (!Files.exists(Path.of(PASSWORD_FILE))) { - throw new IllegalStateException("Could not find " + PASSWORD_FILE - + ". Please create a Snowflake account, get the password and store it in this project in " - + PASSWORD_FILE + "."); - } - if (!Files.exists(Path.of(ACCOUNTNAME_FILE))) { - throw new IllegalStateException("Could not find " + ACCOUNTNAME_FILE - + ". Please create a Snowflake account, get the accountName (part of the specific login url you get when creating the account) and store it in this project in " - + ACCOUNTNAME_FILE + "."); - } - - this.userName = Files.readString(Path.of(USERNAME_FILE)).replace("\n", "").replace("\r", ""); - this.password = Files.readString(Path.of(PASSWORD_FILE)).replace("\n", "").replace("\r", ""); - this.accountName = Files.readString(Path.of(ACCOUNTNAME_FILE)).replace("\n", "").replace("\r", ""); + TestConfig testConfig = TestConfig.read(); + this.userName = testConfig.getSnowflakeUsername(); + this.password = testConfig.getSnowflakePassword(); + this.accountName = testConfig.getSnowflakeAccountname(); } private static void uploadDriverToBucket(final ExasolContainer> container) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java b/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java index 9b116e0..d791be5 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/TestConfig.java @@ -1,4 +1,57 @@ package com.exasol.adapter.dialects.snowflake; +import java.io.*; +import java.nio.file.*; +import java.util.Properties; +import java.util.logging.Logger; + public class TestConfig { -} + private static final Logger LOGGER = Logger.getLogger(TestConfig.class.getName()); + private static final Path CONFIG_FILE = Paths.get("test.properties").toAbsolutePath(); + private final Properties properties; + + private TestConfig(final Properties properties) { + this.properties = properties; + } + + public static TestConfig read() { + final Path file = CONFIG_FILE; + if (!Files.exists(file)) { + throw new IllegalStateException("Config file " + file + " does not exist."); + } + return new TestConfig(loadProperties(file)); + } + + private static Properties loadProperties(final Path configFile) { + LOGGER.info(() -> "Reading config file " + configFile); + try (InputStream stream = Files.newInputStream(configFile)) { + final Properties props = new Properties(); + props.load(stream); + return props; + } catch (final IOException exception) { + throw new UncheckedIOException("Error reading config file " + configFile, exception); + } + } + + + private String getMandatoryValue(final String param) { + if (!properties.containsKey(param)) { + throw new IllegalStateException( + "Config file " + CONFIG_FILE + " does not contain parameter '" + param + "'"); + } + return this.properties.getProperty(param); + } + + public String getSnowflakeUsername() { + return getMandatoryValue("snowflake.username"); + } + + public String getSnowflakeAccountname() { + return getMandatoryValue("snowflake.accountname"); + } + + public String getSnowflakePassword() { + return getMandatoryValue("snowflake.password"); + } + +} \ No newline at end of file From 4ded1469d3d33c9fe9493cf0c5ed40af8be299c9 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 26 Sep 2024 07:06:27 -0400 Subject: [PATCH 32/64] change release date --- doc/changes/changes_0.1.0.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 9bd4687..5c28dce 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2024-09-25 +# Virtual Schema for Snowflake 0.1.0, released 2024-09-26 Code name: First version of the Snowflake virtual schema @@ -44,16 +44,16 @@ Consider this a first and early-access release. * Added `com.exasol:project-keeper-maven-plugin:4.3.3` * Added `io.github.zlika:reproducible-build-maven-plugin:0.16` * Added `org.apache.maven.plugins:maven-assembly-plugin:3.7.1` -* Added `org.apache.maven.plugins:maven-clean-plugin:2.5` +* Added `org.apache.maven.plugins:maven-clean-plugin:3.2.0` * Added `org.apache.maven.plugins:maven-compiler-plugin:3.13.0` * Added `org.apache.maven.plugins:maven-dependency-plugin:3.6.1` -* Added `org.apache.maven.plugins:maven-deploy-plugin:2.7` +* Added `org.apache.maven.plugins:maven-deploy-plugin:3.1.1` * Added `org.apache.maven.plugins:maven-enforcer-plugin:3.5.0` * Added `org.apache.maven.plugins:maven-failsafe-plugin:3.2.5` -* Added `org.apache.maven.plugins:maven-install-plugin:2.4` +* Added `org.apache.maven.plugins:maven-install-plugin:3.1.1` * Added `org.apache.maven.plugins:maven-jar-plugin:3.4.1` -* Added `org.apache.maven.plugins:maven-resources-plugin:2.6` -* Added `org.apache.maven.plugins:maven-site-plugin:3.3` +* Added `org.apache.maven.plugins:maven-resources-plugin:3.3.1` +* Added `org.apache.maven.plugins:maven-site-plugin:3.12.1` * Added `org.apache.maven.plugins:maven-surefire-plugin:3.2.5` * Added `org.apache.maven.plugins:maven-toolchains-plugin:3.2.0` * Added `org.basepom.maven:duplicate-finder-maven-plugin:2.0.1` @@ -62,4 +62,4 @@ Consider this a first and early-access release. * Added `org.codehaus.mojo:versions-maven-plugin:2.16.2` * Added `org.jacoco:jacoco-maven-plugin:0.8.12` * Added `org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121` -* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` \ No newline at end of file +* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` From f485b525bbe0d835ea7ab47884b522e0add59d95 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 26 Sep 2024 07:23:09 -0400 Subject: [PATCH 33/64] pk dependency update fix --- doc/changes/changes_0.1.0.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 5c28dce..3370dcb 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -44,16 +44,16 @@ Consider this a first and early-access release. * Added `com.exasol:project-keeper-maven-plugin:4.3.3` * Added `io.github.zlika:reproducible-build-maven-plugin:0.16` * Added `org.apache.maven.plugins:maven-assembly-plugin:3.7.1` -* Added `org.apache.maven.plugins:maven-clean-plugin:3.2.0` +* Added `org.apache.maven.plugins:maven-clean-plugin:2.5` * Added `org.apache.maven.plugins:maven-compiler-plugin:3.13.0` * Added `org.apache.maven.plugins:maven-dependency-plugin:3.6.1` -* Added `org.apache.maven.plugins:maven-deploy-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-deploy-plugin:2.7` * Added `org.apache.maven.plugins:maven-enforcer-plugin:3.5.0` * Added `org.apache.maven.plugins:maven-failsafe-plugin:3.2.5` -* Added `org.apache.maven.plugins:maven-install-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-install-plugin:2.4` * Added `org.apache.maven.plugins:maven-jar-plugin:3.4.1` -* Added `org.apache.maven.plugins:maven-resources-plugin:3.3.1` -* Added `org.apache.maven.plugins:maven-site-plugin:3.12.1` +* Added `org.apache.maven.plugins:maven-resources-plugin:2.6` +* Added `org.apache.maven.plugins:maven-site-plugin:3.3` * Added `org.apache.maven.plugins:maven-surefire-plugin:3.2.5` * Added `org.apache.maven.plugins:maven-toolchains-plugin:3.2.0` * Added `org.basepom.maven:duplicate-finder-maven-plugin:2.0.1` @@ -62,4 +62,4 @@ Consider this a first and early-access release. * Added `org.codehaus.mojo:versions-maven-plugin:2.16.2` * Added `org.jacoco:jacoco-maven-plugin:0.8.12` * Added `org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121` -* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` +* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0 From ec29ed682b5470007fef7cec97a728d826f8b4d7 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 26 Sep 2024 07:29:50 -0400 Subject: [PATCH 34/64] fix changes file --- doc/changes/changes_0.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 3370dcb..6f7edd4 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -62,4 +62,4 @@ Consider this a first and early-access release. * Added `org.codehaus.mojo:versions-maven-plugin:2.16.2` * Added `org.jacoco:jacoco-maven-plugin:0.8.12` * Added `org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121` -* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0 +* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` \ No newline at end of file From efc6290bd08ecd0f4d42bfc02dc70b61f2f9dd2f Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Thu, 26 Sep 2024 10:07:11 -0400 Subject: [PATCH 35/64] update testcontainers to also work with testcontainer versions > 8.29.0 (fix nullpointer exception) --- doc/changes/changes_0.1.0.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 6f7edd4..81ef55e 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -23,7 +23,7 @@ Consider this a first and early-access release. ### Test Dependency Updates * Added `com.exasol:autogenerated-resource-verifier-java:0.1.2` -* Added `com.exasol:exasol-testcontainers:7.0.1` +* Added `com.exasol:exasol-testcontainers:7.1.1` * Added `com.exasol:hamcrest-resultset-matcher:1.6.4` * Added `com.exasol:test-db-builder-java:3.5.3` * Added `com.exasol:udf-debugging-java:0.6.11` diff --git a/pom.xml b/pom.xml index e32d619..ac76a10 100644 --- a/pom.xml +++ b/pom.xml @@ -56,7 +56,7 @@ com.exasol exasol-testcontainers - 7.0.1 + 7.1.1 test From ffd37f74d05a2503c7bb99b95b14ffb9fe654b31 Mon Sep 17 00:00:00 2001 From: Christoph Pirkl Date: Fri, 27 Sep 2024 06:24:18 +0200 Subject: [PATCH 36/64] Fix compile error --- pom.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pom.xml b/pom.xml index ac76a10..25478e1 100644 --- a/pom.xml +++ b/pom.xml @@ -110,6 +110,16 @@ + + org.apache.maven.plugins + maven-compiler-plugin + + + -Xlint:all,-path + -Werror + + + org.apache.maven.plugins maven-assembly-plugin From 6767697065178d0832c023a998d7caf872f39263 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 03:22:05 -0400 Subject: [PATCH 37/64] cleanup code smells after testconfig refactor --- .../snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index dd86f8b..9d73038 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -3,7 +3,6 @@ import static com.exasol.dbbuilder.dialects.exasol.AdapterScript.Language.JAVA; import java.io.*; -import java.nio.file.Files; import java.nio.file.Path; import java.sql.*; import java.util.*; @@ -18,7 +17,6 @@ import com.exasol.errorreporting.ExaError; import com.exasol.udfdebugging.UdfTestSetup; import com.github.dockerjava.api.model.ContainerNetwork; -import org.junit.jupiter.api.Test; /** * This class contains the common integration test setup for all Snowflake virtual schemas. @@ -138,7 +136,7 @@ private Connection getSnowflakeConnection(final String username, final String pa return DriverManager.getConnection(connectStr, properties); } - private void getTestCredentials() throws IOException { + private void getTestCredentials() { TestConfig testConfig = TestConfig.read(); this.userName = testConfig.getSnowflakeUsername(); this.password = testConfig.getSnowflakePassword(); From 3d0230a6752674f9ab28d776ee23d9784d37ad8e Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 03:22:34 -0400 Subject: [PATCH 38/64] release date --- doc/changes/changes_0.1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 81ef55e..84197c5 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2024-09-26 +# Virtual Schema for Snowflake 0.1.0, released 2024-09-27 Code name: First version of the Snowflake virtual schema From a1541c1f1ef8e908b95cf772b892018c58b836f8 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 03:27:16 -0400 Subject: [PATCH 39/64] fix compilation error after refactoring --- ...SnowflakeVirtualSchemaIntegrationTestSetup.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 9d73038..6c22a2b 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -2,7 +2,8 @@ import static com.exasol.dbbuilder.dialects.exasol.AdapterScript.Language.JAVA; -import java.io.*; +import java.io.Closeable; +import java.io.FileNotFoundException; import java.nio.file.Path; import java.sql.*; import java.util.*; @@ -92,13 +93,11 @@ public String getDatabaseName() { } catch (final InterruptedException exception) { Thread.currentThread().interrupt(); throw new IllegalStateException("Thread was interrupted"); - } catch (final IOException e) { - throw new RuntimeException(e); } } private ConnectionDefinition getSnowflakeConnectionDefinition(final String connectionString, final String username, - final String password) { + final String password) { final ConnectionDefinition connectionDefinition; connectionDefinition = this.exasolFactory.createConnectionDefinition("SNOWFLAKE_CONNECTION", connectionString, username, password); @@ -131,13 +130,14 @@ private Connection getSnowflakeConnection(final String username, final String pa String connectStr = System.getenv("SF_JDBC_CONNECT_STRING"); // use the default connection string if it is not set in environment if (connectStr == null) { - connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your account name + connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your + // account name } return DriverManager.getConnection(connectStr, properties); } private void getTestCredentials() { - TestConfig testConfig = TestConfig.read(); + final TestConfig testConfig = TestConfig.read(); this.userName = testConfig.getSnowflakeUsername(); this.password = testConfig.getSnowflakePassword(); this.accountName = testConfig.getSnowflakeAccountname(); @@ -192,7 +192,7 @@ public ExasolContainer> getExasolContainer() { } public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, - final Map additionalProperties) { + final Map additionalProperties) { final Map properties = new HashMap<>(Map.of("CATALOG_NAME", databaseName, // "SCHEMA_NAME", forSnowflakeSchema)); // properties.putAll(additionalProperties); From 9b0eff17efb62b2ce8a328b120909823161f18df Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 05:38:54 -0400 Subject: [PATCH 40/64] reformatted SnowflakeSqlGenerationVisitor --- .../SnowflakeSqlGenerationVisitor.java | 138 +++++++++--------- 1 file changed, 68 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java index 9f45ccd..68b084f 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java @@ -57,12 +57,12 @@ private String getColumnProjectionString(final SqlColumn column, final String pr final ColumnAdapterNotesJsonConverter converter = ColumnAdapterNotesJsonConverter.getInstance(); ColumnMetadata metaData = column.getMetadata(); DataType mappedType = metaData.getType(); - ColumnAdapterNotes columnAdapterNotes= converter.convertFromJsonToColumnAdapterNotes(metaData.getAdapterNotes(), column.getName()); - String sourceTypeName = columnAdapterNotes.getTypeName(); + ColumnAdapterNotes columnAdapterNotes = converter.convertFromJsonToColumnAdapterNotes(metaData.getAdapterNotes(), column.getName()); + String sourceTypeName = columnAdapterNotes.getTypeName(); - return buildColumnProjectionString(sourceTypeName,mappedType, projectionString); // + return buildColumnProjectionString(sourceTypeName, mappedType, projectionString); // } else { - return projectionString; + return projectionString; } } @@ -75,33 +75,33 @@ public String visit(final SqlFunctionScalar function) throws AdapterException { } final ScalarFunction scalarFunction = function.getFunction(); switch (scalarFunction) { - case ADD_DAYS: - return getAddDateTime(argumentsSql, "days"); - case ADD_HOURS: - return getAddDateTime(argumentsSql, "hours"); - case ADD_MINUTES: - return getAddDateTime(argumentsSql, "mins"); - case ADD_SECONDS: - return getAddDateTime(argumentsSql, "secs"); - case ADD_WEEKS: - return getAddDateTime(argumentsSql, "weeks"); - case ADD_YEARS: - return getAddDateTime(argumentsSql, "years"); - case ADD_MONTHS: - return getAddDateTime(argumentsSql, "months"); - case SECOND: - case MINUTE: - case DAY: - case WEEK: - case MONTH: - case YEAR: - return getDateTime(argumentsSql, scalarFunction); - case POSIX_TIME: - return getPosixTime(argumentsSql); - case FLOAT_DIV: - return getCastToDoublePrecisionAndDivide(argumentsSql); - default: - return super.visit(function); + case ADD_DAYS: + return getAddDateTime(argumentsSql, "days"); + case ADD_HOURS: + return getAddDateTime(argumentsSql, "hours"); + case ADD_MINUTES: + return getAddDateTime(argumentsSql, "mins"); + case ADD_SECONDS: + return getAddDateTime(argumentsSql, "secs"); + case ADD_WEEKS: + return getAddDateTime(argumentsSql, "weeks"); + case ADD_YEARS: + return getAddDateTime(argumentsSql, "years"); + case ADD_MONTHS: + return getAddDateTime(argumentsSql, "months"); + case SECOND: + case MINUTE: + case DAY: + case WEEK: + case MONTH: + case YEAR: + return getDateTime(argumentsSql, scalarFunction); + case POSIX_TIME: + return getPosixTime(argumentsSql); + case FLOAT_DIV: + return getCastToDoublePrecisionAndDivide(argumentsSql); + default: + return super.visit(function); } } @@ -136,43 +136,43 @@ private String getDateTime(final List argumentsSql, final ScalarFunction private static void appendDatePart(ScalarFunction scalarFunction, StringBuilder builder) { switch (scalarFunction) { - case SECOND: - builder.append("'SECOND'"); - break; - case MINUTE: - builder.append("'MINUTE'"); - break; - case DAY: - builder.append("'DAY'"); - break; - case WEEK: - builder.append("'WEEK'"); - break; - case MONTH: - builder.append("'MONTH'"); - break; - case YEAR: - builder.append("'YEAR'"); - break; - default: - break; + case SECOND: + builder.append("'SECOND'"); + break; + case MINUTE: + builder.append("'MINUTE'"); + break; + case DAY: + builder.append("'DAY'"); + break; + case WEEK: + builder.append("'WEEK'"); + break; + case MONTH: + builder.append("'MONTH'"); + break; + case YEAR: + builder.append("'YEAR'"); + break; + default: + break; } } private static void appendDecimalSize(ScalarFunction scalarFunction, StringBuilder builder) { switch (scalarFunction) { - case SECOND: - case MINUTE: - case DAY: - case WEEK: - case MONTH: - builder.append("2"); - break; - case YEAR: - builder.append("4"); - break; - default: - break; + case SECOND: + case MINUTE: + case DAY: + case WEEK: + case MONTH: + builder.append("2"); + break; + case YEAR: + builder.append("4"); + break; + default: + break; } } @@ -180,14 +180,12 @@ private String getPosixTime(final List argumentsSql) { return "EXTRACT(EPOCH FROM " + argumentsSql.get(0) + ")"; } - private String buildColumnProjectionString(final String typeName,DataType mappedType, final String projectionString) { - if (typeName.startsWith("NUMBER") && mappedType.getExaDataType() == DataType.ExaDataType.VARCHAR ){ + private String buildColumnProjectionString(final String typeName, DataType mappedType, final String projectionString) { + if (typeName.startsWith("NUMBER") && mappedType.getExaDataType() == DataType.ExaDataType.VARCHAR) { return "'Number precision not supported'"; - } - else if (typeName.startsWith("TIMESTAMPTZ")) { - return "TO_TIMESTAMP_NTZ(" + projectionString +")"; - } - else if (checkIfNeedToCastToVarchar(typeName)) { + } else if (typeName.startsWith("TIMESTAMPTZ")) { + return "TO_TIMESTAMP_NTZ(" + projectionString + ")"; + } else if (checkIfNeedToCastToVarchar(typeName)) { return "CAST(" + projectionString + " as VARCHAR )"; } else if (typeName.startsWith("smallserial")) { return "CAST(" + projectionString + " as SMALLINT )"; From bf90929ed2018b91b2b249f2d63a690c459ce2ab Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 05:39:53 -0400 Subject: [PATCH 41/64] set docker image reference in integration test setup to latest dockerdb version --- .../snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 6c22a2b..93d687a 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -27,7 +27,7 @@ public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { private static final Path PATH_TO_VIRTUAL_SCHEMAS_JAR = Path.of("target", VIRTUAL_SCHEMAS_JAR_NAME_AND_VERSION); private static final String SCHEMA_EXASOL = "SCHEMA_EXASOL"; private static final String ADAPTER_SCRIPT_EXASOL = "ADAPTER_SCRIPT_EXASOL"; - private static final String EXASOL_DOCKER_IMAGE_REFERENCE = "8.24.0"; + private static final String EXASOL_DOCKER_IMAGE_REFERENCE = "8.31.0"; private static final String SNOWFLAKE_CONTAINER_NAME = "localstack/snowflake:14.2"; private static final String JDBC_DRIVER_NAME = "snowflake-jdbc.jar"; From 5f127d3fa0815defa32599e2ae208bd5de67ee6c Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 05:41:39 -0400 Subject: [PATCH 42/64] removed unused dependency + moved dependency to integration test dependency block --- pom.xml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 25478e1..8833b42 100644 --- a/pom.xml +++ b/pom.xml @@ -27,13 +27,6 @@ 3.16.1 - - com.exasol - virtual-schema-common-jdbc - ${vscjdbc.version} - test-jar - test - org.hamcrest hamcrest @@ -53,6 +46,13 @@ test + + com.exasol + virtual-schema-common-jdbc + ${vscjdbc.version} + test-jar + test + com.exasol exasol-testcontainers @@ -65,12 +65,6 @@ ${org.testcontainers.version} test - - org.testcontainers - localstack - 1.19.8 - test - com.exasol test-db-builder-java From 316fee97b48cb92d4dbef3b0f29bfa45637a1f03 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 07:07:32 -0400 Subject: [PATCH 43/64] cleaned up IntegrationTestSetup class --- ...lakeVirtualSchemaIntegrationTestSetup.java | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 93d687a..2c1e021 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -28,12 +28,10 @@ public class SnowflakeVirtualSchemaIntegrationTestSetup implements Closeable { private static final String SCHEMA_EXASOL = "SCHEMA_EXASOL"; private static final String ADAPTER_SCRIPT_EXASOL = "ADAPTER_SCRIPT_EXASOL"; private static final String EXASOL_DOCKER_IMAGE_REFERENCE = "8.31.0"; - private static final String SNOWFLAKE_CONTAINER_NAME = "localstack/snowflake:14.2"; private static final String JDBC_DRIVER_NAME = "snowflake-jdbc.jar"; private static final Path JDBC_DRIVER_PATH = Path.of("target/snowflake-driver/" + JDBC_DRIVER_NAME); - private static final int SNOWFLAKE_PORT = 5432; private final Statement snowflakeStatement; private final ExasolContainer> exasolContainer = new ExasolContainer<>( EXASOL_DOCKER_IMAGE_REFERENCE).withRequiredServices(ExasolService.BUCKETFS, ExasolService.UDF) @@ -56,10 +54,10 @@ public String randomDbAddendum() { final int targetStringLength = 4; final Random random = new Random(); - final String generatedString = random.ints(leftLimit, rightLimit + 1).limit(targetStringLength) + return random.ints(leftLimit, rightLimit + 1).limit(targetStringLength) .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString(); - return generatedString; + } public String getDatabaseName() { @@ -97,7 +95,7 @@ public String getDatabaseName() { } private ConnectionDefinition getSnowflakeConnectionDefinition(final String connectionString, final String username, - final String password) { + final String password) { final ConnectionDefinition connectionDefinition; connectionDefinition = this.exasolFactory.createConnectionDefinition("SNOWFLAKE_CONNECTION", connectionString, username, password); @@ -119,20 +117,13 @@ private Connection getSnowflakeConnection(final String username, final String pa // build connection properties final Properties properties = new Properties(); - properties.put("user", username); // replace "" with your username - properties.put("password", password); // replace "" with your password - properties.put("account", accountname); // replace "" with your account name - properties.put("db", this.databaseName); // replace "" with target database name - properties.put("schema", "TESTSCHEMA"); // replace "" with target schema name - // properties.put("tracing", "on"); - - // create a new connection - String connectStr = System.getenv("SF_JDBC_CONNECT_STRING"); - // use the default connection string if it is not set in environment - if (connectStr == null) { - connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your - // account name - } + properties.put("user", username); + properties.put("password", password); + properties.put("account", accountname); + properties.put("db", this.databaseName); + properties.put("schema", "TESTSCHEMA"); + + String connectStr = "jdbc:snowflake://" + accountname + ".snowflakecomputing.com"; // replace accountName with your account name return DriverManager.getConnection(connectStr, properties); } @@ -192,7 +183,7 @@ public ExasolContainer> getExasolContainer() { } public VirtualSchema createVirtualSchema(final String forSnowflakeSchema, - final Map additionalProperties) { + final Map additionalProperties) { final Map properties = new HashMap<>(Map.of("CATALOG_NAME", databaseName, // "SCHEMA_NAME", forSnowflakeSchema)); // properties.putAll(additionalProperties); From 1a82a38499b09683c2da8af8d426c94f61e04a38 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 07:07:59 -0400 Subject: [PATCH 44/64] removed // --- .../dialects/snowflake/SnowflakeSqlGenerationVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java index 68b084f..4efc0b8 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java @@ -60,7 +60,7 @@ private String getColumnProjectionString(final SqlColumn column, final String pr ColumnAdapterNotes columnAdapterNotes = converter.convertFromJsonToColumnAdapterNotes(metaData.getAdapterNotes(), column.getName()); String sourceTypeName = columnAdapterNotes.getTypeName(); - return buildColumnProjectionString(sourceTypeName, mappedType, projectionString); // + return buildColumnProjectionString(sourceTypeName, mappedType, projectionString); } else { return projectionString; } From 19adae7fa4bb2f742ccb8fe7710ad8c7ee77cb80 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 08:55:56 -0400 Subject: [PATCH 45/64] simplified snowflake database setup and teardown in IT class --- .../snowflake/SnowflakeSqlDialectIT.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index 9507be4..028d55b 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -44,19 +44,11 @@ class SnowflakeSqlDialectIT { @BeforeAll static void beforeAll() throws SQLException { final Statement statementSnowflake = SETUP.getSnowflakeStatement(); - try { - statementSnowflake.execute("CREATE DATABASE " + SETUP.getDatabaseName()); - } catch (final Exception e) { - } - try { - statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE + " CASCADE"); - statementSnowflake.execute("DROP SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE + " CASCADE"); - } catch (final Exception e) { - - } + statementSnowflake.execute("CREATE DATABASE " + SETUP.getDatabaseName()); statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE); statementSnowflake.execute("CREATE SCHEMA " + SCHEMA_SNOWFLAKE_UPPERCASE_TABLE); + createSnowflakeTestTableSimple(statementSnowflake); createSnowflakeTestTableAllDataTypes(statementSnowflake); createTestTablesForJoinTests(SCHEMA_SNOWFLAKE); @@ -71,11 +63,7 @@ static void beforeAll() throws SQLException { @AfterAll static void afterAll() throws SQLException { final Statement statementSnowflake = SETUP.getSnowflakeStatement(); - try { statementSnowflake.execute("DROP DATABASE " + SETUP.getDatabaseName() + " CASCADE;"); - } catch (final Exception e) { - - } } private static void createSnowflakeTestTableSimple(final Statement statementSnowflake) throws SQLException { From 05c43fa0b32aec34fe3ca1d421d395542e2d55e6 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Fri, 27 Sep 2024 08:56:33 -0400 Subject: [PATCH 46/64] PR Review: requested changes to user guide --- doc/user_guide/snowflake_user_guide.md | 105 ++++++++++++------------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/doc/user_guide/snowflake_user_guide.md b/doc/user_guide/snowflake_user_guide.md index 1ce757d..fb1f441 100644 --- a/doc/user_guide/snowflake_user_guide.md +++ b/doc/user_guide/snowflake_user_guide.md @@ -27,7 +27,7 @@ INSERTSIZE=-1 NOSECURITY=YES ``` -Make sure there's a newline at the end of the `settings.cfg` file, as shown above, or it will not be properly read out, the EXALoader will display an error message. +Make sure there's an empty line at the end of the `settings.cfg` file, as shown above, or it will not be properly read out, the EXALoader will display an error message. | Variable | Description | |-----------------------------------------|----------------------------------| @@ -56,7 +56,7 @@ CREATE OR REPLACE JAVA ADAPTER SCRIPT ADAPTER.SNOWFLAKE_JDBC_ADAPTER AS ## Defining a Named Connection -Define the connection to the Snowflake database as shown below. We recommend using TLS to secure the connection. +Define the connection to the Snowflake database as shown below. ```sql CREATE OR REPLACE CONNECTION SNOWFLAKE_CONNECTION @@ -65,9 +65,8 @@ USER '' IDENTIFIED BY ''; ``` -| Variable | Description | -|----------|-------------| - +| Variable | Description | +|-----------------|-------------------------------------------------------------------------| | ` CONNECTION_NAME = 'SNOWFLAKE_CONNECTION'; ``` -| Variable | Description | -|-------------------------|-----------------------------------------------------------------------------------------------------| -| `` | Name of the virtual schema you want to use. | -| `` | Name of the catalog, usally equivalent to the name of the Snowflake database. Please use UPPERCASE. | -| `` | Name of the database schema you want to use in the Snowflake database. Please use UPPERCASE. | +| Variable | Description | +|-------------------------|------------------------------------------------------------------------------------------------------| +| `` | Name of the virtual schema you want to use. | +| `` | Name of the catalog, usually equivalent to the name of the Snowflake database. Please use UPPERCASE. | +| `` | Name of the database schema you want to use in the Snowflake database. Please use UPPERCASE. | -For additional parameters coming from the base library see also [Adapter Properties for JDBC-Based Virtual Schemas](https://github.com/exasol/virtual-schema-common-jdbc#adapter-properties-for-jdbc-based-virtual-schemas). +For additional parameters (optional), see also [Adapter Properties for JDBC-Based Virtual Schemas](https://github.com/exasol/virtual-schema-common-jdbc#adapter-properties-for-jdbc-based-virtual-schemas). ## Data Types Conversion -| Snowflake Data Type | Supported | Converted Exasol Data Type | Known limitations | -|--------------------------|--------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| -| BIGINT | ✓ | DECIMAL(19,0) | | -| BIGSERIAL | ✓ | DECIMAL(19,0) | | -| BIT | ✓ | BOOLEAN | | -| BIT VARYING | ✓ | VARCHAR(5) | | -| BOX | ✓ | VARCHAR(2000000) | | -| BYTEA | ✓ | VARCHAR(2000000) | | -| BOOLEAN | ✓ | BOOLEAN | | -| CHARACTER | ✓ | CHAR | | -| CHARACTER VARYING | ✓ | VARCHAR | | -| CIDR | ✓ | VARCHAR(2000000) | | -| CIRCLE | ✓ | VARCHAR(2000000) | | -| DATE | ✓ | DATE | | -| DOUBLE PRECISION | ✓ | DOUBLE | | -| INET | ✓ | VARCHAR(2000000) | | -| INTEGER | ✓ | DECIMAL(10,0) | | -| INTERVAL | ✓ | VARCHAR(2000000) | | -| JSON | ✓ | VARCHAR(2000000) | | -| JSONB | ✓ | VARCHAR(2000000) | | -| LINE | ✓ | VARCHAR(2000000) | | -| LSEG | ✓ | VARCHAR(2000000) | | -| MACADDR | ✓ | VARCHAR(2000000) | | -| MONEY | ✓ | DOUBLE | | -| NUMERIC | ✓ | VARCHAR(2000000) | Stored in Exasol as VARCHAR, because Snowflake NUMERIC values can exceed Exasol Decimal limit which makes it impossible to use Virtual Schemas. | -| PATH | ✓ | VARCHAR(2000000) | | -| POINT | ✓ | VARCHAR(2000000) | | -| POLYGON | ✓ | VARCHAR(2000000) | | -| REAL | ✓ | DOUBLE | | -| SMALLINT | ✓ | DECIMAL(5,0) | | -| SMALLSERIAL | ? (untested) | | | -| SERIAL | ? (untested) | | | -| TEXT | ✓ | VARCHAR(2000000) | | -| TIME | ✓ | VARCHAR(2000000) | | -| TIME WITH TIME ZONE | ✓ | VARCHAR(2000000) | | -| TIMESTAMP | ✓ | TIMESTAMP | | -| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP | | -| TSQUERY | ✓ | VARCHAR(2000000) | | -| TSVECTOR | ✓ | VARCHAR(2000000) | | -| UUID | ✓ | VARCHAR(2000000) | | -| XML | ✓ | VARCHAR(2000000) | | +| Snowflake Data Type | Supported | Converted Exasol Data Type | Known limitations | +|--------------------------|---------------|----------------------------|---------------------------------------------------------------------------------------------------------------------| +| BIGINT | ✓ | VARCHAR(2000000) | Alias for NUMBER(38,0) in Snowflake | +| BIGSERIAL | ✓ | DECIMAL(19,0) | | +| BIT | ✓ | BOOLEAN | | +| BIT VARYING | ✓ | VARCHAR(5) | | +| BOX | ✓ | VARCHAR(2000000) | | +| BYTEA | ✓ | VARCHAR(2000000) | | +| BOOLEAN | ✓ | BOOLEAN | | +| CHARACTER | ✓ | VARCHAR | | +| CHARACTER VARYING | ✓ | VARCHAR | | +| CIDR | ✓ | VARCHAR(2000000) | | +| CIRCLE | ✓ | VARCHAR(2000000) | | +| DATE | ✓ | DATE | | +| DOUBLE PRECISION | ✓ | DOUBLE | | +| INET | ✓ | VARCHAR(2000000) | | +| INTEGER | ✓ | DECIMAL(10,0) | | +| INTERVAL | ✓ | VARCHAR(2000000) | | +| JSON | ✓ | VARCHAR(2000000) | | +| JSONB | ✓ | VARCHAR(2000000) | | +| LINE | ✓ | VARCHAR(2000000) | | +| LSEG | ✓ | VARCHAR(2000000) | | +| MACADDR | ✓ | VARCHAR(2000000) | | +| MONEY | ✓ | DOUBLE | | +| NUMERIC | ✓ | DECIMAL/VARCHAR(2000000) | Stored in Exasol as DECIMAL or VARCHAR, because Snowflake NUMERIC values can exceed Exasol NUMERIC PRECISION limit. | +| PATH | ✓ | VARCHAR(2000000) | | +| POINT | ✓ | VARCHAR(2000000) | | +| POLYGON | ✓ | VARCHAR(2000000) | | +| REAL | ✓ | DOUBLE | | +| SMALLINT | ✓ | VARCHAR(2000000) | Alias for NUMBER(38,0) | +| SMALLSERIAL | (unsupported) | | | +| SERIAL | (unsupported) | | | +| TEXT | ✓ | VARCHAR(2000000) | | +| TIME | ✓ | TIME | | +| TIME WITH TIME ZONE | ✓ | VARCHAR(2000000) | | +| TIMESTAMP | ✓ | TIMESTAMP | | +| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP (UTC) | | +| TSQUERY | ✓ | VARCHAR(2000000) | | +| TSVECTOR | ✓ | VARCHAR(2000000) | | +| UUID | ✓ | VARCHAR(2000000) | | +| XML | ✓ | VARCHAR(2000000) | | From fb01a6b9f620a625a3fa3ec474486812bc8f2d8f Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 03:58:30 -0400 Subject: [PATCH 47/64] removed 'serial' cases in visitor since these don't exist in snowflake --- .../dialects/snowflake/SnowflakeSqlGenerationVisitor.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java index 4efc0b8..397a4f7 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java @@ -187,12 +187,6 @@ private String buildColumnProjectionString(final String typeName, DataType mappe return "TO_TIMESTAMP_NTZ(" + projectionString + ")"; } else if (checkIfNeedToCastToVarchar(typeName)) { return "CAST(" + projectionString + " as VARCHAR )"; - } else if (typeName.startsWith("smallserial")) { - return "CAST(" + projectionString + " as SMALLINT )"; - } else if (typeName.startsWith("serial")) { - return "CAST(" + projectionString + " as INTEGER )"; - } else if (typeName.startsWith("bigserial")) { - return "CAST(" + projectionString + " as BIGINT )"; } else if (TYPE_NAMES_NOT_SUPPORTED.contains(typeName)) { return "cast('" + typeName + " NOT SUPPORTED' as varchar) as not_supported"; } else { From d741c7cf754b9abad7db9f8729b3a1bf24c9051c Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 03:59:55 -0400 Subject: [PATCH 48/64] fix formatting --- .../SnowflakeColumnMetadataReader.java | 24 +++++++++---------- .../snowflake/SnowflakeMetadataReader.java | 2 +- .../snowflake/SnowflakeSqlDialectFactory.java | 4 ++-- .../SnowflakeTableMetadataReader.java | 2 +- .../SnowflakeColumnMetadataReaderTest.java | 3 +-- .../snowflake/SnowflakeSqlDialectIT.java | 2 +- .../snowflake/SnowflakeSqlDialectTest.java | 4 ++-- .../SnowflakeSqlGenerationVisitorTest.java | 12 +++++----- .../docgeneration/CapabilitiesReport.java | 2 +- .../exasol/closeafterall/CloseAfterAll.java | 2 +- .../closeafterall/CloseAfterAllExtension.java | 2 +- 11 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java index f2f9ae2..ed1bc7f 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java @@ -24,7 +24,7 @@ public class SnowflakeColumnMetadataReader extends BaseColumnMetadataReader { * @param identifierConverter converter between source and Exasol identifiers */ public SnowflakeColumnMetadataReader(final Connection connection, final AdapterProperties properties, - final IdentifierConverter identifierConverter) { + final IdentifierConverter identifierConverter) { super(connection, properties, identifierConverter); } @@ -36,16 +36,16 @@ public SnowflakeColumnMetadataReader(final Connection connection, final AdapterP @Override public DataType mapJdbcType(final JDBCTypeDescription jdbcTypeDescription) { switch (jdbcTypeDescription.getJdbcType()) { - case Types.OTHER: - return mapJdbcTypeOther(jdbcTypeDescription); - case Types.SQLXML: - case Types.DISTINCT: - case Types.BINARY: - return DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8); - case Types.TIMESTAMP_WITH_TIMEZONE: - return DataType.createTimestamp(false); - default: - return super.mapJdbcType(jdbcTypeDescription); + case Types.OTHER: + return mapJdbcTypeOther(jdbcTypeDescription); + case Types.SQLXML: + case Types.DISTINCT: + case Types.BINARY: + return DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8); + case Types.TIMESTAMP_WITH_TIMEZONE: + return DataType.createTimestamp(false); + default: + return super.mapJdbcType(jdbcTypeDescription); } } @@ -67,7 +67,7 @@ protected boolean isVarBitColumn(final JDBCTypeDescription jdbcTypeDescription) @Override public String readColumnName(final ResultSet columns) throws SQLException { - return super.readColumnName(columns); + return super.readColumnName(columns); } @Override diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java index e323fdd..4f8e6c0 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java @@ -39,7 +39,7 @@ public ColumnMetadataReader createColumnMetadataReader() { @Override public String getSchemaNameFilter() { - return this.properties.getSchemaName().replace("_","\\_").toUpperCase(); + return this.properties.getSchemaName().replace("_", "\\_").toUpperCase(); } } \ No newline at end of file diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java index 1f4db40..7b4aef9 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectFactory.java @@ -10,7 +10,7 @@ * Factory for the Snowflake SQL dialect. */ public class SnowflakeSqlDialectFactory implements SqlDialectFactory { - + @Override public String getSqlDialectName() { return SnowflakeSqlDialect.NAME; @@ -20,7 +20,7 @@ public String getSqlDialectName() { public SqlDialect createSqlDialect(final ConnectionFactory connectionFactory, final AdapterProperties properties) { return new SnowflakeSqlDialect(connectionFactory, properties); } - + @Override public String getSqlDialectVersion() { final VersionCollector versionCollector = new VersionCollector( diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java index d7124ac..687403d 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeTableMetadataReader.java @@ -25,7 +25,7 @@ public class SnowflakeTableMetadataReader extends BaseTableMetadataReader { * @param identifierConverter converter between source and Exasol identifiers */ public SnowflakeTableMetadataReader(final Connection connection, final ColumnMetadataReader columnMetadataReader, - final AdapterProperties properties, final IdentifierConverter identifierConverter) { + final AdapterProperties properties, final IdentifierConverter identifierConverter) { super(connection, columnMetadataReader, properties, identifierConverter); } } \ No newline at end of file diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java index c758103..15cb163 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReaderTest.java @@ -42,7 +42,7 @@ protected DataType mapJdbcType(final int type) { return this.columnMetadataReader.mapJdbcType(jdbcTypeDescription); } - @ValueSource(ints = { Types.SQLXML, Types.DISTINCT }) + @ValueSource(ints = {Types.SQLXML, Types.DISTINCT}) @ParameterizedTest void testMapJdbcTypeFallbackToMaxVarChar(final int type) { assertThat(mapJdbcType(type), equalTo(DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8))); @@ -54,5 +54,4 @@ void testMapJdbcTypeFallbackToParent() { } - } diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java index 028d55b..5327f86 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectIT.java @@ -63,7 +63,7 @@ static void beforeAll() throws SQLException { @AfterAll static void afterAll() throws SQLException { final Statement statementSnowflake = SETUP.getSnowflakeStatement(); - statementSnowflake.execute("DROP DATABASE " + SETUP.getDatabaseName() + " CASCADE;"); + statementSnowflake.execute("DROP DATABASE " + SETUP.getDatabaseName() + " CASCADE;"); } private static void createSnowflakeTestTableSimple(final Statement statementSnowflake) throws SQLException { diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java index f268462..4e55d9d 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java @@ -87,8 +87,8 @@ void testGetCapabilities() { ); } - @ValueSource(strings = { "ab:E'ab'", "a'b:E'a''b'", "a''b:E'a''''b'", "'ab':E'''ab'''", "a\\\\b:E'a\\\\\\\\b'", - "a\\'b:E'a\\\\''b'" }) + @ValueSource(strings = {"ab:E'ab'", "a'b:E'a''b'", "a''b:E'a''''b'", "'ab':E'''ab'''", "a\\\\b:E'a\\\\\\\\b'", + "a\\'b:E'a\\\\''b'"}) @ParameterizedTest void testGetLiteralString(final String definition) { assertThat(this.dialect.getStringLiteral(definition.substring(0, definition.indexOf(':'))), diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java index 1f9a7e5..e3e6d99 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitorTest.java @@ -38,13 +38,13 @@ void beforeEach(@Mock final ConnectionFactory connectionFactoryMock) { this.visitor = new SnowflakeSqlGenerationVisitor(dialect, context); } - @CsvSource({ "ADD_DAYS, days", // + @CsvSource({"ADD_DAYS, days", // "ADD_HOURS, hours", // "ADD_MINUTES, mins", // "ADD_SECONDS, secs", // "ADD_YEARS, years", // "ADD_WEEKS, weeks", // - "ADD_MONTHS, months" }) + "ADD_MONTHS, months"}) @ParameterizedTest void testVisitSqlFunctionScalarAddDate(final ScalarFunction scalarFunction, final String expected) throws AdapterException { @@ -54,7 +54,7 @@ void testVisitSqlFunctionScalarAddDate(final ScalarFunction scalarFunction, fina } private SqlFunctionScalar createSqlFunctionScalarForDateTest(final ScalarFunction scalarFunction, - final int numericValue) { + final int numericValue) { final List arguments = new ArrayList<>(); arguments.add(new SqlColumn(1, ColumnMetadata.builder().name("test_column") @@ -64,15 +64,15 @@ private SqlFunctionScalar createSqlFunctionScalarForDateTest(final ScalarFunctio return new SqlFunctionScalar(scalarFunction, arguments); } - @CsvSource({ "SECOND, SECOND, 2", // + @CsvSource({"SECOND, SECOND, 2", // "MINUTE, MINUTE, 2", // "DAY, DAY, 2", // "WEEK, WEEK, 2", // "MONTH, MONTH, 2", // - "YEAR, YEAR, 4" }) + "YEAR, YEAR, 4"}) @ParameterizedTest void testVisitSqlFunctionScalarDatetime(final ScalarFunction scalarFunction, final String expected, - final String decimalSize) throws AdapterException { + final String decimalSize) throws AdapterException { final SqlFunctionScalar sqlFunctionScalar = createSqlFunctionScalarForDateTest(scalarFunction, 0); assertThat(this.visitor.visit(sqlFunctionScalar), equalTo("CAST(DATE_PART('" + expected + "',\"test_column\") AS DECIMAL(" + decimalSize + ",0))")); diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java b/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java index a749989..1a03311 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/docgeneration/CapabilitiesReport.java @@ -53,7 +53,7 @@ public Path getPathOfGeneratedFile() { } private void reportCapabilities(final String headline, final String tableHeader, final T[] all, - final Set enabled, final LinedStringBuilder reportBuilder) { + final Set enabled, final LinedStringBuilder reportBuilder) { reportBuilder.appendLine("## " + headline); reportBuilder.appendLine(); final Table.Builder tableBuilder = new Table.Builder().withAlignments(Table.ALIGN_LEFT, Table.ALIGN_CENTER) diff --git a/src/test/java/com/exasol/closeafterall/CloseAfterAll.java b/src/test/java/com/exasol/closeafterall/CloseAfterAll.java index 81d2191..5548f6b 100644 --- a/src/test/java/com/exasol/closeafterall/CloseAfterAll.java +++ b/src/test/java/com/exasol/closeafterall/CloseAfterAll.java @@ -8,7 +8,7 @@ * In order to make this work you need to add the {@link CloseAfterAllExtension} to your test class. *

*/ -@Target({ ElementType.FIELD }) +@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface CloseAfterAll { } diff --git a/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java b/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java index 5b2da71..2026ce4 100644 --- a/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java +++ b/src/test/java/com/exasol/closeafterall/CloseAfterAllExtension.java @@ -41,7 +41,7 @@ private void closeObject(final Field field, final Object annotatedObject) throws ((Closeable) annotatedObject).close(); } else { throw new IllegalStateException(ExaError.messageBuilder("E-VSSF-9").message( - "Could not close the field {{field}} annotated with @CloseAfterAll since it does not implement Closable.") + "Could not close the field {{field}} annotated with @CloseAfterAll since it does not implement Closable.") .parameter("field", field.getName()).toString()); } } From 8b85fe568ca7ab2eb41448322815c0b98cb40a2d Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 04:27:28 -0400 Subject: [PATCH 49/64] changes to visibility and logger settings --- .../dialects/snowflake/SnowflakeColumnMetadataReader.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java index ed1bc7f..da65283 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeColumnMetadataReader.java @@ -49,19 +49,19 @@ public DataType mapJdbcType(final JDBCTypeDescription jdbcTypeDescription) { } } - protected DataType mapJdbcTypeOther(final JDBCTypeDescription jdbcTypeDescription) { + private DataType mapJdbcTypeOther(final JDBCTypeDescription jdbcTypeDescription) { if (isVarBitColumn(jdbcTypeDescription)) { final int n = jdbcTypeDescription.getPrecisionOrSize(); - LOGGER.finer(() -> "Mapping Snowflake datatype \"OTHER:varbit\" to VARCHAR(" + n + ")"); + LOGGER.finest(() -> "Mapping Snowflake datatype \"OTHER:varbit\" to VARCHAR(" + n + ")"); return DataType.createVarChar(n, DataType.ExaCharset.UTF8); } else { - LOGGER.finer(() -> "Mapping Snowflake datatype \"" + jdbcTypeDescription.getTypeName() + LOGGER.finest(() -> "Mapping Snowflake datatype \"" + jdbcTypeDescription.getTypeName() + "\" to maximum VARCHAR()"); return DataType.createMaximumSizeVarChar(DataType.ExaCharset.UTF8); } } - protected boolean isVarBitColumn(final JDBCTypeDescription jdbcTypeDescription) { + private boolean isVarBitColumn(final JDBCTypeDescription jdbcTypeDescription) { return jdbcTypeDescription.getTypeName().equals(SNOWFLAKE_VARBIT_TYPE_NAME); } From c68f6a377b72232824f283b83c43fdbab2236834 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 04:28:13 -0400 Subject: [PATCH 50/64] changes to exception handling --- .../SnowflakeVirtualSchemaIntegrationTestSetup.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java index 2c1e021..64be266 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeVirtualSchemaIntegrationTestSetup.java @@ -86,7 +86,7 @@ public String getDatabaseName() { this.adapterScript = createAdapterScript(exasolSchema); final String connectionString = getSnowflakeConnectionString(accountName); connectionDefinition = getSnowflakeConnectionDefinition(connectionString, userName, password); - } catch (final SQLException | BucketAccessException | TimeoutException exception) { + } catch (final SQLException | BucketAccessException | TimeoutException | ClassNotFoundException exception ) { throw new IllegalStateException("Failed to created snowflake test setup.", exception); } catch (final InterruptedException exception) { Thread.currentThread().interrupt(); @@ -108,13 +108,8 @@ private String getSnowflakeConnectionString(final String accountname) { } private Connection getSnowflakeConnection(final String username, final String password, final String accountname) - throws SQLException { - try { + throws SQLException, ClassNotFoundException { Class.forName("net.snowflake.client.jdbc.SnowflakeDriver"); - } catch (final ClassNotFoundException ex) { - System.err.println("Driver not found"); - } - // build connection properties final Properties properties = new Properties(); properties.put("user", username); From ef3bfbed3699ea9d873de76ef69edecccf8998a2 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 04:29:53 -0400 Subject: [PATCH 51/64] Removed unnecessary whitespace --- .../adapter/dialects/snowflake/SnowflakeMetadataReader.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java index 4f8e6c0..3d4386f 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeMetadataReader.java @@ -41,5 +41,4 @@ public ColumnMetadataReader createColumnMetadataReader() { public String getSchemaNameFilter() { return this.properties.getSchemaName().replace("_", "\\_").toUpperCase(); } - } \ No newline at end of file From 0b4f9df2cb0f21a20004a3f5e4b0a60fac9dc231 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 04:30:18 -0400 Subject: [PATCH 52/64] Changed comment as suggested --- .../exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java index 312b63c..a428b85 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java @@ -82,7 +82,7 @@ private static Capabilities createCapabilityList() { } /** - * This class gets all {@link ScalarFunctionCapability}s that are not explicitly excluded by + * Return all {@link ScalarFunctionCapability}s that are not explicitly excluded by * {@link #DISABLED_SCALAR_FUNCTION}. * * @return list enabled scalar function capabilities From 25aa6f275f2ecf67d4f26fae3f44a4ef7ae2e98a Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 08:22:09 -0400 Subject: [PATCH 53/64] user guide, redid conversion/mapping table --- doc/user_guide/snowflake_user_guide.md | 52 ++++++-------------------- 1 file changed, 11 insertions(+), 41 deletions(-) diff --git a/doc/user_guide/snowflake_user_guide.md b/doc/user_guide/snowflake_user_guide.md index fb1f441..1c54651 100644 --- a/doc/user_guide/snowflake_user_guide.md +++ b/doc/user_guide/snowflake_user_guide.md @@ -99,44 +99,14 @@ For additional parameters (optional), see also [Adapter Properties for JDBC-Base ## Data Types Conversion -| Snowflake Data Type | Supported | Converted Exasol Data Type | Known limitations | -|--------------------------|---------------|----------------------------|---------------------------------------------------------------------------------------------------------------------| -| BIGINT | ✓ | VARCHAR(2000000) | Alias for NUMBER(38,0) in Snowflake | -| BIGSERIAL | ✓ | DECIMAL(19,0) | | -| BIT | ✓ | BOOLEAN | | -| BIT VARYING | ✓ | VARCHAR(5) | | -| BOX | ✓ | VARCHAR(2000000) | | -| BYTEA | ✓ | VARCHAR(2000000) | | -| BOOLEAN | ✓ | BOOLEAN | | -| CHARACTER | ✓ | VARCHAR | | -| CHARACTER VARYING | ✓ | VARCHAR | | -| CIDR | ✓ | VARCHAR(2000000) | | -| CIRCLE | ✓ | VARCHAR(2000000) | | -| DATE | ✓ | DATE | | -| DOUBLE PRECISION | ✓ | DOUBLE | | -| INET | ✓ | VARCHAR(2000000) | | -| INTEGER | ✓ | DECIMAL(10,0) | | -| INTERVAL | ✓ | VARCHAR(2000000) | | -| JSON | ✓ | VARCHAR(2000000) | | -| JSONB | ✓ | VARCHAR(2000000) | | -| LINE | ✓ | VARCHAR(2000000) | | -| LSEG | ✓ | VARCHAR(2000000) | | -| MACADDR | ✓ | VARCHAR(2000000) | | -| MONEY | ✓ | DOUBLE | | -| NUMERIC | ✓ | DECIMAL/VARCHAR(2000000) | Stored in Exasol as DECIMAL or VARCHAR, because Snowflake NUMERIC values can exceed Exasol NUMERIC PRECISION limit. | -| PATH | ✓ | VARCHAR(2000000) | | -| POINT | ✓ | VARCHAR(2000000) | | -| POLYGON | ✓ | VARCHAR(2000000) | | -| REAL | ✓ | DOUBLE | | -| SMALLINT | ✓ | VARCHAR(2000000) | Alias for NUMBER(38,0) | -| SMALLSERIAL | (unsupported) | | | -| SERIAL | (unsupported) | | | -| TEXT | ✓ | VARCHAR(2000000) | | -| TIME | ✓ | TIME | | -| TIME WITH TIME ZONE | ✓ | VARCHAR(2000000) | | -| TIMESTAMP | ✓ | TIMESTAMP | | -| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP (UTC) | | -| TSQUERY | ✓ | VARCHAR(2000000) | | -| TSVECTOR | ✓ | VARCHAR(2000000) | | -| UUID | ✓ | VARCHAR(2000000) | | -| XML | ✓ | VARCHAR(2000000) | | +| Snowflake Data Type | Supported | Converted Exasol Data Type | Known limitations | +|------------------------------------------------------------------------------------------------|-----------|----------------------------|-------------------------------------| +| NUMBER,DECIMAL , DEC , NUMERIC | ✓ | DECIMAL(36,0) | Precision > 36 is not supported. | +| INT , INTEGER , BIGINT , SMALLINT , TINYINT , BYTEINT | ✓ | VARCHAR(2000000) | Alias for NUMBER(38,0) in Snowflake | +| BOOLEAN | ✓ | BOOLEAN | | +| VARCHAR,CHAR, CHARACTER, NCHAR, STRING, TEXT, NVARCHAR, NVARCHAR2, CHAR VARYING, NCHAR VARYING | ✓ | VARCHAR | | +| DATE | ✓ | DATE | | +| FLOAT,DOUBLE PRECISION,DOUBLE , REAL | ✓ | DOUBLE | | +| TIME | ✓ | TIME | | +| TIMESTAMP | ✓ | TIMESTAMP | | +| TIMESTAMP WITH TIME ZONE | ✓ | TIMESTAMP (UTC) | | \ No newline at end of file From fe23e7b963c163702942298b94b7cef434095ca0 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:22:24 -0400 Subject: [PATCH 54/64] design and dev guide --- doc/design.md | 10 +++++++++- doc/developer_guide/developer_guide.md | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 doc/developer_guide/developer_guide.md diff --git a/doc/design.md b/doc/design.md index 49a8da2..c61c306 100644 --- a/doc/design.md +++ b/doc/design.md @@ -1 +1,9 @@ -# Design for the Snowflake Virtual Schema adapter \ No newline at end of file +# Design for the Snowflake Virtual Schema adapter + +## General design notes +The snowflake virtual schema's capabilities, mapping and query pushdown are mainly based on the existing PostgreSql virtual schema. +This is because the PostgreSql database approaches Snowflake the closest, functionality wise. + +## Notes on NUMERIC +The numeric datatype has a higher supported precision in Snowflake (38 vs 36 in Snowflake): +If the precision is higher than 36 the column gets mapped to varchar and will display 'Precision not supported' as value. \ No newline at end of file diff --git a/doc/developer_guide/developer_guide.md b/doc/developer_guide/developer_guide.md new file mode 100644 index 0000000..3333707 --- /dev/null +++ b/doc/developer_guide/developer_guide.md @@ -0,0 +1,24 @@ +# Developers Guide + +## Running the integration tests + +Located in `SnowflakeSqlDialectIT.java` + +### Locally + +You need to add a `test.properties` file to the project folder that has the following structure: +` +snowflake.username = +snowflake.accountname = +snowflake.password = +` + +### In the GitHub CI + +The credentials are stored in the following GitHub repository secrets: +- `USERNAME` +- `ACCOUNTNAME` +- `PASSWORD` +and get read out by the relevant CI workflows. + + From 3a2122a6a5ea3ee884e8c20d17941157e2a211aa Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:24:18 -0400 Subject: [PATCH 55/64] Changes to readme.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0d79772..161bb1a 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ # Overview +Snowflake Virtual Schema (short "VSSF") is an implementation of a [Virtual Schema](https://docs.exasol.com/db/latest/database_concepts/virtual_schemas.htm). + The **Snowflake Virtual Schema** provides an abstraction layer that makes an external [Snowflake](https://www.Snowflake.org/) database accessible from an Exasol database through regular SQL commands. The contents of the external Snowflake database are mapped to virtual tables which look like and can be queried as any regular Exasol table. If you want to set up a Virtual Schema for a different database system, please head over to the [Virtual Schemas Repository][virtual-schemas]. @@ -33,10 +35,12 @@ If you want to set up a Virtual Schema for a different database system, please h * [Changelog](doc/changes/changelog.md) * [Dependencies](dependencies.md) -Find all the documentation in the [Virtual Schemas project][vs-doc]. +Find all the documentation in the [Virtual Schemas project](https://github.com/exasol/virtual-schemas). ## Information for Developers +* [Design](doc/design.md) +* [Developer guide](doc/developer_guide/developer_guide.md) * [Virtual Schema API Documentation](https://github.com/exasol/virtual-schema-common-java/blob/main/doc/development/api/virtual_schema_api.md) * [Remote logging](https://docs.exasol.com/db/latest/database_concepts/virtual_schema/logging.htm) From 62c062cbf77782bce054382bd5e764e9b7a76498 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:26:36 -0400 Subject: [PATCH 56/64] Note on deviations --- doc/design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/design.md b/doc/design.md index c61c306..0a5aeee 100644 --- a/doc/design.md +++ b/doc/design.md @@ -2,7 +2,7 @@ ## General design notes The snowflake virtual schema's capabilities, mapping and query pushdown are mainly based on the existing PostgreSql virtual schema. -This is because the PostgreSql database approaches Snowflake the closest, functionality wise. +This is because the PostgreSql database approaches Snowflake the closest, functionality wise. Currently there are few deviations but this is expected to change. ## Notes on NUMERIC The numeric datatype has a higher supported precision in Snowflake (38 vs 36 in Snowflake): From 2ef8b179e7d7d53ca7f0f1328017ac331cce4bac Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:27:49 -0400 Subject: [PATCH 57/64] Update settings.json to remove debug status and use latest docker image --- .vscode/settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a7ae59b..7fc4fe8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,12 +12,12 @@ "java.test.config": { "vmArgs": [ "-Djava.util.logging.config.file=src/test/resources/logging.properties", - "-Dtest.debug='true'", - "-Dcom.exasol.dockerdb.image=8.24.0" + "-Dcom.exasol.dockerdb.image=8.31.0" ] }, "sonarlint.connectedMode.project": { "connectionId": "exasol", "projectKey": "com.exasol:snowflake-virtual-schema" - } + }, + "java.configuration.updateBuildConfiguration": "automatic" } \ No newline at end of file From ea4af97c3eda095bccc1e98629c8fe591a51b564 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:28:23 -0400 Subject: [PATCH 58/64] Removed note on scalar functions --- .../exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java index a428b85..4170887 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialect.java @@ -31,7 +31,6 @@ public class SnowflakeSqlDialect extends AbstractSqlDialect { private static final Set DISABLED_SCALAR_FUNCTION = Set.of( /* - * Implementation for `BETWEEN` time functions is not supported. For more information see `design.md` file, * `Scalar Functions` section */ SECONDS_BETWEEN, MINUTES_BETWEEN, HOURS_BETWEEN, DAYS_BETWEEN, MONTHS_BETWEEN, YEARS_BETWEEN, // @@ -62,7 +61,7 @@ public class SnowflakeSqlDialect extends AbstractSqlDialect { /* * IMPORTANT! Before adding new capabilities, check the `doc/design.md` file if there is a note on why the - * capability is not supported. it. + * capability is not supported. */ private static Capabilities createCapabilityList() { return Capabilities.builder() From b84a62f119f45c715786878960774d5898f0a213 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:28:57 -0400 Subject: [PATCH 59/64] Removed unused localstack dependency, PK update to changes file --- doc/changes/changes_0.1.0.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 84197c5..5080b42 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -35,7 +35,6 @@ Consider this a first and early-access release. * Added `org.junit.jupiter:junit-jupiter:5.10.1` * Added `org.mockito:mockito-junit-jupiter:5.10.0` * Added `org.testcontainers:junit-jupiter:1.19.4` -* Added `org.testcontainers:localstack:1.19.8` ### Plugin Dependency Updates From eb4ef8be2549b476055f60bcd8cda67b2ff127fc Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Mon, 30 Sep 2024 09:29:22 -0400 Subject: [PATCH 60/64] Removed newline --- .../adapter/dialects/snowflake/SnowflakeSqlDialectTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java index 4e55d9d..522f0f1 100644 --- a/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java +++ b/src/test/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlDialectTest.java @@ -100,7 +100,6 @@ void testGetLiteralStringNull() { assertThat(this.dialect.getStringLiteral(null), CoreMatchers.equalTo("NULL")); } - @Test void testValidateDatabaseProperty() throws PropertyValidationException { final SqlDialect sqlDialect = new SnowflakeSqlDialect(null, new AdapterProperties(Map.of( // From 54914b8684919548132d78ea64110f8c43b84afc Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 1 Oct 2024 05:07:55 -0400 Subject: [PATCH 61/64] PK/dependencies/doc fix --- dependencies.md | 3 +-- doc/changes/changes_0.1.0.md | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/dependencies.md b/dependencies.md index 0ad946f..a51a6b7 100644 --- a/dependencies.md +++ b/dependencies.md @@ -13,13 +13,12 @@ | Dependency | License | | ----------------------------------------------- | --------------------------------------------- | -| [Virtual Schema Common JDBC][0] | [MIT License][1] | | [Hamcrest][6] | [BSD License 3][7] | | [JUnit Jupiter (Aggregator)][8] | [Eclipse Public License v2.0][9] | | [mockito-junit-jupiter][10] | [MIT][11] | +| [Virtual Schema Common JDBC][0] | [MIT License][1] | | [Test containers for Exasol on Docker][12] | [MIT License][13] | | [Testcontainers :: JUnit Jupiter Extension][14] | [MIT][15] | -| [Testcontainers :: Localstack][14] | [MIT][15] | | [Test Database Builder for Java][16] | [MIT License][17] | | [Matcher for SQL Result Sets][18] | [MIT License][19] | | [udf-debugging-java][20] | [MIT License][21] | diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 5080b42..c156458 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -61,4 +61,4 @@ Consider this a first and early-access release. * Added `org.codehaus.mojo:versions-maven-plugin:2.16.2` * Added `org.jacoco:jacoco-maven-plugin:0.8.12` * Added `org.sonarsource.scanner.maven:sonar-maven-plugin:4.0.0.4121` -* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` \ No newline at end of file +* Added `org.sonatype.ossindex.maven:ossindex-maven-plugin:3.2.0` From 2c6864b49c15d372e215b972cce8be5e4b85b02d Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 1 Oct 2024 05:08:22 -0400 Subject: [PATCH 62/64] removed unused code --- .../snowflake/SnowflakeSqlGenerationVisitor.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java index 397a4f7..73e06cc 100644 --- a/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java +++ b/src/main/java/com/exasol/adapter/dialects/snowflake/SnowflakeSqlGenerationVisitor.java @@ -16,9 +16,6 @@ * This class generates SQL queries for the {@link SnowflakeSqlDialect}. */ public class SnowflakeSqlGenerationVisitor extends SqlGenerationVisitor { - private static final List TYPE_NAMES_REQUIRING_CAST = List.of("varbit", "point", "line", "lseg", "box", - "path", "polygon", "circle", "cidr", "citext", "inet", "macaddr", "interval", "json", "jsonb", "uuid", - "tsquery", "tsvector", "xml", "smallserial", "serial", "bigserial"); private static final List TYPE_NAMES_NOT_SUPPORTED = List.of("bytea"); /** @@ -31,14 +28,6 @@ public SnowflakeSqlGenerationVisitor(final SqlDialect dialect, final SqlGenerati super(dialect, context); } - protected List getListOfTypeNamesRequiringCast() { - return TYPE_NAMES_REQUIRING_CAST; - } - - protected List getListOfTypeNamesNotSupported() { - return TYPE_NAMES_NOT_SUPPORTED; - } - @Override protected String representAnyColumnInSelectList() { return SqlConstants.ONE; From 04f7a68d6c181830f5115e7f4d6abbd81fca01d0 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 1 Oct 2024 05:22:16 -0400 Subject: [PATCH 63/64] release date --- doc/changes/changes_0.1.0.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index c156458..3aa7429 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -1,4 +1,4 @@ -# Virtual Schema for Snowflake 0.1.0, released 2024-09-27 +# Virtual Schema for Snowflake 0.1.0, released 2024-10-01 Code name: First version of the Snowflake virtual schema @@ -43,16 +43,16 @@ Consider this a first and early-access release. * Added `com.exasol:project-keeper-maven-plugin:4.3.3` * Added `io.github.zlika:reproducible-build-maven-plugin:0.16` * Added `org.apache.maven.plugins:maven-assembly-plugin:3.7.1` -* Added `org.apache.maven.plugins:maven-clean-plugin:2.5` +* Added `org.apache.maven.plugins:maven-clean-plugin:3.2.0` * Added `org.apache.maven.plugins:maven-compiler-plugin:3.13.0` * Added `org.apache.maven.plugins:maven-dependency-plugin:3.6.1` -* Added `org.apache.maven.plugins:maven-deploy-plugin:2.7` +* Added `org.apache.maven.plugins:maven-deploy-plugin:3.1.1` * Added `org.apache.maven.plugins:maven-enforcer-plugin:3.5.0` * Added `org.apache.maven.plugins:maven-failsafe-plugin:3.2.5` -* Added `org.apache.maven.plugins:maven-install-plugin:2.4` +* Added `org.apache.maven.plugins:maven-install-plugin:3.1.1` * Added `org.apache.maven.plugins:maven-jar-plugin:3.4.1` -* Added `org.apache.maven.plugins:maven-resources-plugin:2.6` -* Added `org.apache.maven.plugins:maven-site-plugin:3.3` +* Added `org.apache.maven.plugins:maven-resources-plugin:3.3.1` +* Added `org.apache.maven.plugins:maven-site-plugin:3.12.1` * Added `org.apache.maven.plugins:maven-surefire-plugin:3.2.5` * Added `org.apache.maven.plugins:maven-toolchains-plugin:3.2.0` * Added `org.basepom.maven:duplicate-finder-maven-plugin:2.0.1` From 719866498e5c034c6aeec22d1bf0c234cd0bbf15 Mon Sep 17 00:00:00 2001 From: Pieterjan Spoelders Date: Tue, 1 Oct 2024 10:45:38 -0400 Subject: [PATCH 64/64] fix dependencies in changes doc --- doc/changes/changes_0.1.0.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/changes/changes_0.1.0.md b/doc/changes/changes_0.1.0.md index 3aa7429..05e133a 100644 --- a/doc/changes/changes_0.1.0.md +++ b/doc/changes/changes_0.1.0.md @@ -43,16 +43,16 @@ Consider this a first and early-access release. * Added `com.exasol:project-keeper-maven-plugin:4.3.3` * Added `io.github.zlika:reproducible-build-maven-plugin:0.16` * Added `org.apache.maven.plugins:maven-assembly-plugin:3.7.1` -* Added `org.apache.maven.plugins:maven-clean-plugin:3.2.0` +* Added `org.apache.maven.plugins:maven-clean-plugin:2.5` * Added `org.apache.maven.plugins:maven-compiler-plugin:3.13.0` * Added `org.apache.maven.plugins:maven-dependency-plugin:3.6.1` -* Added `org.apache.maven.plugins:maven-deploy-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-deploy-plugin:2.7` * Added `org.apache.maven.plugins:maven-enforcer-plugin:3.5.0` * Added `org.apache.maven.plugins:maven-failsafe-plugin:3.2.5` -* Added `org.apache.maven.plugins:maven-install-plugin:3.1.1` +* Added `org.apache.maven.plugins:maven-install-plugin:2.4` * Added `org.apache.maven.plugins:maven-jar-plugin:3.4.1` -* Added `org.apache.maven.plugins:maven-resources-plugin:3.3.1` -* Added `org.apache.maven.plugins:maven-site-plugin:3.12.1` +* Added `org.apache.maven.plugins:maven-resources-plugin:2.6` +* Added `org.apache.maven.plugins:maven-site-plugin:3.3` * Added `org.apache.maven.plugins:maven-surefire-plugin:3.2.5` * Added `org.apache.maven.plugins:maven-toolchains-plugin:3.2.0` * Added `org.basepom.maven:duplicate-finder-maven-plugin:2.0.1`